rareMax Опубликовано 25 июля, 2016 Опубликовано 25 июля, 2016 Добрый день. Хочу узнать как правильно возвращать объекты в функции, что бы не было утечки памяти. Данная проблема на данный момент воспроизводится в проекте TelegaPI. Ниже упрощенный код с проекта для запросов на сервер: function TTelegramBot.API<T>(const Method: String; Parameters: TDictionary<String, TValue>): T; var lHttp: THTTPClient; lHttpResponse: IHTTPResponse; lApiResponse: TtgApiResponse<T>; lURL_TELEG: String; begin lHttp := THTTPClient.Create; try lURL_TELEG := 'https://api.telegram.org/bot' + FToken + '/' + Method; // Преобразовуем параметры в строку, если нужно if Assigned(Parameters) then lHttpResponse := lHttp.Post(lURL_TELEG, ParamsToFormData(Parameters)) else lHttpResponse := lHttp.Get(lURL_TELEG); lApiResponse := TtgApiResponse<T>.FromJSON(lHttpResponse.ContentAsString); Result := lApiResponse.ResultObject; finally FreeAndNil(lHttp); { Ниже утечка памяти. Если расскоментировать - тогда не будет возращаться результат функций } // if Assigned(lApiResponse) then // lApiResponse.Free; end; end; В таком виде не освобождается lApiResponse - в результате утечка памяти. Если раскоментировать 2 последние строки - тогда в результате функции будет пустой объект. Прошу опытных людей в этом плане рассказать что мне нужно подправить. Спасибо. Цитата
Кривяков Виталий Опубликовано 25 июля, 2016 Опубликовано 25 июля, 2016 Наверное самый простой способ, это поменять прототип функции на function TTelegramBot.API<T>(const Method: String; Parameters: TDictionary<String, TValue>): TtgApiResponse<T>; И возвращать Result := TtgApiResponse<T>.FromJSON(lHttpResponse.ContentAsString); Ну и соответственно уничтожать объект в вызывающем методе, после того, как он не нужен. rareMax и Евгений Корепов 2 Цитата
rareMax Опубликовано 25 июля, 2016 Автор Опубликовано 25 июля, 2016 Сейчас попробую на интерфейсы перевести. Если не получится - буду вашим способом пользоваться(хотя для конечного пользователя гемор лишний будет). Спасибо за совет. Rusland и Pax Beach 2 Цитата
Евгений Корепов Опубликовано 26 июля, 2016 Опубликовано 26 июля, 2016 Операция Result := lApiResponse.ResultObject; копирует в Result ссылку на тот же самый объект. И логично что при попытке освободить его функция вернет пустоту, так как вы освобождаете и результат функции. Как вариант можно использовать функцию Assign - копирование объекта в Result, тогда освобождение lApiResponse.Free не затронет результат возвращаемый функцией. rareMax и Равиль Зарипов (ZuBy) 2 Цитата
rareMax Опубликовано 22 декабря, 2016 Автор Опубликовано 22 декабря, 2016 (изменено) Как подсказал @kami можно вернуть копию объекта. Выглядит это так: lApiResponse := TtgApiResponse<T>.FromJSON(lHttpResponse.ContentAsString); Result := lApiResponse.ResultObject; //!! lApiResponse.ResultObject := Default (T); finally FreeAndNil(lHttp); if Assigned(lApiResponse) then lApiResponse.Free; end; Изменено 22 декабря, 2016 пользователем RareGod Цитата
kami Опубликовано 22 декабря, 2016 Опубликовано 22 декабря, 2016 1 час назад, RareGod сказал: Выглядит это так: После "!!" требуется перевод строки. На самом деле возвращается не копия объекта. Суть сей манипуляции в том, что нам нужно как-то вернуть экземпляр нужного типа из контейнера (lAPIResponse), не дав ему уничтожиться при удалении этого контейнера. Теоретически, здесь можно было бы сделать lAPIResponse.ResultObject:=nil; в этом случае нужный нам объект не будет уничтожен при удалении контейнера, но и не будет потерян, потому что он уже сидит в Result. Но lAPIResponse - дженериковский объект. Т.е. мы не можем заранее сказать, что в ResultObject будет объект, а не какой-нибудь integer. И тут приходит на выручку функция Default. Для классового типа она вернет nil, для integer - 0 ну и так далее. rareMax и Равиль Зарипов (ZuBy) 2 Цитата
Рекомендуемые сообщения
Присоединяйтесь к обсуждению
Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.