Arhn - архитектура программирования

Как вы передаете объекты между функциями?

Предположим, у меня есть функция:

function someFunction: TStringList;  
begin  
  result:=TStringList.Create;  
  if someConditionIsTrue then  
    result:=doSomething;  
  //other code  
end; 

И функция doSomething:

function doSomething: TStringList;
begin
  result:=TStringList.Create;
  result.Add(something);
end;

Если я запускаю этот код, все работает, как и ожидалось, но мне все еще интересно, является ли это «правильным» способом передачи объекта, такого как список строк?

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

05.07.2016

  • Вы уже вызываете утечку памяти только в первом примере кода, даже не используя его где-либо еще. Сначала вы создаете экземпляр, затем полностью игнорируете этот экземпляр и создаете на его месте другой. 05.07.2016
  • Ваш код создает 2 экземпляра TStringlist, что приведет к утечке памяти. И тот, который возвращает someFunction, будет отличаться в зависимости от значения someConditionIsTrue. Айоу, вам не нужен .Create в doSomething. 05.07.2016
  • Нет правильного пути. Вам нужно выработать свое соглашение о том, какая сторона освобождает память, и строго ему следовать. Кроме того, вам нужно обратить внимание на подсказки компилятора, они указывают вам на проблему с первым фрагментом. 05.07.2016
  • Кроме того, это уже обсуждалось много раз, например, stackoverflow.com/questions/1894217 05.07.2016
  • @FreeConsulting -- я ценю ваш ответ. Просто для протокола: мой компилятор (Lazarus/Free Pascal) не дает никаких намеков на эту проблему. 05.07.2016
  • @AlC, в двух словах, вы выделяете память с 1-м присвоением Result и перезаписываете указатель на нее 2-м присвоением, в то время как вам нужно сохранить этот указатель, чтобы освободить эту память. По сути, точно такая же проблема, с которой вы можете столкнуться при вызове функций этого дизайна. 05.07.2016
  • AI C — вы можете обойти эту проблему, используя интерфейс с поддержкой ARC из Jedi CodeLib (который поддерживается FPC) — указатели iJclStringList вместо TStrings/TStringList. Это автоматически освободит неиспользуемые списки строк. Тем не менее было бы не очень эффективно выделять объект списка строк только для того, чтобы сразу удалить его и создать новый. 05.07.2016
  • @AIC Хотя вы, вероятно, можете обойти проблему, как вы описываете, это все же не очень хорошая привычка. Всегда лучше освободить его самостоятельно, это хорошая практика. Никогда не полагайтесь на третью сторону, чтобы сделать то, что вы должны делать. :) 06.07.2016

Ответы:


1

«Правильный» подход заключается в том, чтобы вы установили свои собственные правила уничтожения вещей. Можно создавать объекты в результате функции, но только если вы следуете собственным строгим правилам.

В вашем случае SomeFunction имеет утечку памяти. Сначала вы создаете TStringList, а затем, если выполняется какое-то условие, вы создаете на его месте еще один TStringList, полностью игнорируя первый. Таким образом, утечка памяти.

DoSomething не должна быть функцией, возвращающей список строк, если есть вероятность, что он уже создан. Вместо этого просто сделайте это процедурой...

procedure DoSomething(AList: TStringList);
begin
  AList.Add(Something);
end;

Как только вы это сделаете, SomeFunction должно выглядеть так:

function someFunction: TStringList;  
begin  
  Result:= TStringList.Create;  
  if someConditionIsTrue then  
    DoSomething(Result);  
  //other code  
end; 

"Списки строк никогда не освобождаются"

Я надеюсь, что это не по замыслу. Все, что вы создаете, в какой-то момент должно быть освобождено, особенно если у вас есть функции, создающие результат. Единственным исключением является случай, когда вы создаете что-то, что живет на протяжении всего времени работы приложения, и даже в этом случае их освобождение в любом случае является крайней точкой соприкосновения.


В этой заметке единственный раз, когда я когда-либо создавал объект в результате функции, это когда я инкапсулирую несколько строк кода, которые в противном случае дублировались бы много раз. Например, создание запроса.

Вместо того, чтобы повторять этот код...

Q:= TADOQuery.Create(nil);
Q.Connection:= MyDatabaseConnection;
Q.SetSomeOtherProperties;

... Я поместил его в функцию...

function CreateQuery: TADOQuery;
begin
  Result:= TADOQuery.Create(nil);
  Result.Connection:= MyDatabaseConnection;
  Result.SetSomeOtherProperties;
end;

Затем я могу просто вызывать эту функцию всякий раз, когда мне нужно повторить этот код...

Q:= CreateQuery;
05.07.2016
  • Я помню, как вы дали мне хороший ответ на вопрос, который я задал несколько лет назад. Так что еще раз спасибо за ответ :-] 05.07.2016
  • Утечки исключений CreateQuery возникают после создания объекта 06.07.2016
  • @David Действительно, это всего лишь очень сырой и минимальный образец кода. 06.07.2016
  • И спрашивающий собирается его скопировать и рискует утечкой. Стоит уточнить эти детали. Вы бы никогда не написали такой код, я верю. Ответ Кена показывает, как защитить ресурс. 06.07.2016
  • FWIW, о возврате объектов из функций: заголовок ="почему процедуры для создания объектов предпочтительнее функций"> stackoverflow.com/questions/7423604/ 07.07.2016

  • 2

    Строковые списки никогда не освобождаются

    Что само по себе является проблемой. Как упоминалось в комментариях, это создает утечки памяти. В общем, я не одобряю функции, которые создают объекты и передают права собственности через свои результаты. Когда мне нужно это сделать, я обычно называю свою функцию "Create*", чтобы как можно более явно указать, что вызывающий объект отвечает за освобождение памяти.

    С учетом сказанного, более элегантный шаблон для достижения того, что вам нужно:

    procedure someFunction;  
    var vStrings : TStringList;
    begin  
      vStrings := TStringList.Create;  
      try
        if someConditionIsTrue then  
          doSomething(vStrings);  
        //other code  
      finally
        vStrings.Free;
      end;
    end;
    
    procedure doSomething(AStrings : TStringList);
    begin
      AStrings.Add(something);
    end;
    

    Если вам действительно нужна ваша "someFunction" для возврата TStringList и вы не хотите получать ее через параметр, вот как правильно управлять ею, чтобы избежать утечек памяти.

    function CreateAndInitStrings : TStringList;  
    begin  
      Result := TStringList.Create;  
      try
        if someConditionIsTrue then  
          doSomething(Result);  
        //other code  
      except
        Result.Free;
        raise;
      end;
    end;
    
    05.07.2016
  • Err, imo procedure someFunction неудачный; возможно procedure NotActuallyaFunction. 05.07.2016
  • Я сохранил ту же семантику, что и в вопросе, чтобы сделать соответствие как можно более явным. 05.07.2016
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..