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 не затронет результат возвращаемый функцией. Равиль Зарипов (ZuBy) и rareMax 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 ну и так далее. Равиль Зарипов (ZuBy) и rareMax 2 Цитата Ссылка на комментарий
Рекомендуемые сообщения
Присоединяйтесь к обсуждению
Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.