Перейти к содержанию
Fire Monkey от А до Я

Передача объекта в результат функции


Рекомендуемые сообщения

Добрый день. Хочу узнать как правильно возвращать объекты в функции, что бы не было утечки памяти. Данная проблема на данный момент воспроизводится в проекте 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 последние строки - тогда в результате функции будет пустой объект. Прошу опытных людей в этом плане рассказать что мне нужно подправить. Спасибо.

Ссылка на комментарий

Наверное самый простой способ, это поменять прототип функции на

function TTelegramBot.API<T>(const Method: String;
  Parameters: TDictionary<String, TValue>): TtgApiResponse<T>;

И возвращать
 

Result := TtgApiResponse<T>.FromJSON(lHttpResponse.ContentAsString);

Ну и соответственно уничтожать объект в вызывающем методе, после того, как он не нужен.

Ссылка на комментарий

Сейчас попробую на интерфейсы перевести. Если не получится - буду вашим способом пользоваться(хотя для конечного пользователя гемор лишний будет). Спасибо за совет.

Ссылка на комментарий

Операция Result := lApiResponse.ResultObject; копирует в Result ссылку на тот же самый объект. И логично что при попытке освободить его функция вернет пустоту, так как вы освобождаете и результат функции. Как вариант можно использовать функцию Assign - копирование объекта в Result, тогда освобождение lApiResponse.Free не затронет результат возвращаемый функцией.

Ссылка на комментарий
  • 4 месяца спустя...

Как подсказал @kami можно вернуть копию объекта. Выглядит это так:

    lApiResponse := TtgApiResponse<T>.FromJSON(lHttpResponse.ContentAsString);
    Result := lApiResponse.ResultObject;
   //!! lApiResponse.ResultObject := Default (T);
  finally
    FreeAndNil(lHttp);
    if Assigned(lApiResponse) then
       lApiResponse.Free;
  end;

 

Изменено пользователем RareGod
Ссылка на комментарий
1 час назад, RareGod сказал:

Выглядит это так:

После "!!" требуется перевод строки.

На самом деле возвращается не копия объекта. Суть сей манипуляции в том, что нам нужно как-то вернуть экземпляр нужного типа из контейнера (lAPIResponse), не дав ему уничтожиться при удалении этого контейнера.

Теоретически, здесь можно было бы сделать lAPIResponse.ResultObject:=nil; в этом случае нужный нам объект не будет уничтожен при удалении контейнера, но и не будет потерян, потому что он уже сидит в Result.

Но lAPIResponse - дженериковский объект. Т.е. мы не можем заранее сказать, что в ResultObject  будет объект, а не какой-нибудь integer.

И тут приходит на выручку функция Default. Для классового типа она вернет nil, для integer - 0 ну и так далее.

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...