Получение объекта в результате от func/proc в Delphi

Правило с goto, что мы используем, состоит в том, что goto хорошо к для переходящего вперед к единственной точке очистки выхода в функции. В действительно комплексных функциях мы ослабляем то правило позволить другой переход вперед. В обоих случаях мы избегаем глубоко вложенный, если операторы, которые часто происходят при проверке кода ошибки, которая помогает удобочитаемости и maintance.

9
задан Juraj Blahunka 8 November 2009 в 17:52
поделиться

6 ответов

Лучших методов нет. Однако главное, что вы должны сделать, это убедиться, что всегда ясно, кто несет ответственность за уничтожение объекта в любой момент времени, даже когда возникает исключение.

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

function Func: TMyObj;
begin
  Result := TMyObj.Create;
  try
    Result.X := Y;
  except
    Result.Free;
    raise;
  end;
end;

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

O := Func;
try
  writeln(O.X);
finally
  O.Free;
end;

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


Когда вызывающий объект создает объект, а вы передаете его другой функции для его инициализации, не превращайте параметр в параметр «var». Это накладывает определенные ограничения на вызывающего объекта, который должен использовать переменную точно того типа, который запрашивается функцией, даже если вместо этого был создан какой-то тип-потомок.

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

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

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

8
ответ дан 4 December 2019 в 13:47
поделиться

Это зависит от времени жизни объекта и от того, кто за него отвечает. В большинстве случаев объекты должны создаваться и уничтожаться одной и той же сущностью.

Допустим, ваш метод заполняет TStringList результатами синтаксического анализа файла. Должны ли вы позволить этой функции создать TStringList или вы должны создать его и передать в качестве ссылки?

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

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

4
ответ дан 4 December 2019 в 13:47
поделиться

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

procedure Proc (Obj : TMyObject)
begin
  Obj.SomeProperty := 'SomeValue';
  ...
end;

Код вызова:

Obj := TMyObject.Create;
try
  Proc (Obj);
finally
  FreeAndNil (Obj);
end;    

Это позволяет избежать путаницы в отношении того, кто должен освободить объект.

3
ответ дан 4 December 2019 в 13:47
поделиться

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

Таким образом, обычные подписи моих функций

function Func(o:tMyO): TMyO;
begin
  // ....
  Result := o;
end;

, таким образом, я могу сделать либо

   o := func(TMyO.create);

, либо

  o := TMyO.create;
  // ...
  func(o);
2
ответ дан 4 December 2019 в 13:47
поделиться

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

Однако, это возможно, только если вызывающий знает точный тип возвращаемого элемента, а не супертип. Например:

var E: TEmployee;

E := CreateEmployee(EmployeeID);  // Could return TEmployee or subclasses TManager or TRetiredEmployee

try

    E.SendEmail(MessageText);
    if (E is TRetiredEmployee) then
        E.PrintLetter;

finally

    E.Free;

end;

В подобных случаях я считаю полезным включить слово «Create» или другой индикатор в имя вызываемой мной фабричной функции.

1
ответ дан 4 December 2019 в 13:47
поделиться

Я часто использую конструкцию

FUNCTION SomeFunction(SL : TStrings = NIL) : TStrings;
  BEGIN
    IF Assigned(SL) THEN Result:=SL ELSE Result:=TStringList.Create;
    // Use Result for the remainder of the function
  END;

Таким образом, я могу использовать ее как ПРОЦЕДУРУ с переданной ссылкой, так и как ФУНКЦИЮ, которая создает сам экземпляр.

-3
ответ дан 4 December 2019 в 13:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: