ООП эквивалентно цепочке goto для освобождения ресурсов при ошибке? - PullRequest
0 голосов
/ 26 мая 2018

В C я использовал цепочки goto для освобождения ресурсов при ошибке, как рекомендовано здесь .Работая с Delphi, я столкнулся со следующей ситуацией, когда я хочу изящно обработать исчерпание памяти, а также предотвратить утечки памяти:

New(A);
A.DoSomething;
New(A.B);
A.B.DoSomething;
New(A.C);
A.C.DoSomething;

Как я понимаю, способ проверки исчерпания памяти заключается в перехвате исключенияна New.Допустим, все функции DoSomething выдают Exception в случае ошибки.Стандарт кодирования SEI CERT рекомендует против проверки внутриполосных ошибок и против с использованием исключений для потока управления , по крайней мере для Java, что я считаю очень разумным.Я не уверен, как справиться с этой ситуацией, имея в виду эти рекомендации.Моя идея состояла в том, чтобы сделать что-то вроде

function AllocStuff : TA;
begin
  New(Result);
  Result.B := nil;
  Result.C := nil;    
  Result.DoSomething;    
  New(Result.B);
  Result.B.DoSomething;
  New(Result.C);
  Result.C.DoSomething;
end;

Перехват исключений на вызывающем абоненте:

procedure QuestionableControlFlow;
var
  A : TA;
begin
  A := nil;
  try
    A := AllocStuff;
    DoSomethingWith(A);
    Dispose(A);
  except on E : Exception do
    begin
      if (A <> nil) then
        begin
          if (A.B <> nil) then
            begin
              if (A.C <> nil)  then
                begin
                  Dispose(A.C);
                end;
              Dispose(A.B);
            end;
          Dispose(A);                    
        end;
    end;
end;

Это так плохо, как кажется?Смешивание goto с except казалось хуже, и это было все, о чем я мог думать до сих пор.

Ответы [ 2 ]

0 голосов
/ 26 мая 2018

Ваш AllocStuff() должен использовать try/except для перехвата ошибок, чтобы он не возвращал недействительные данные:

function AllocStuff : TA;
begin
  New(Result);
  try
    Result.B := nil;
    Result.C := nil;    
    Result.DoSomething;    
    New(Result.B);
    try
      Result.B.DoSomething;
      New(Result.C);
      try
        Result.C.DoSomething;
      except
        Dispose(Result.C);
        raise;
      end;
    except
      Dispose(Result.B);
      raise;
    end;
  except
    Dispose(Result);
    raise;
  end;
end;

И тогда вызывающая сторона может использовать try/finally для освобождения того, что возвращает AllocStuff():

procedure QuestionableControlFlow;
var
  A : TA;
begin
  A := AllocStuff;
  try
    DoSomethingWith(A);
  finally
    Dispose(A.C);
    Dispose(A.B);
    Dispose(A);
  end;
end;
0 голосов
/ 26 мая 2018

В Delphi вы используете try/finally для неуправляемого ресурса ресурса.

Например,

obj := TObject.Create;
try
  obj.DoSomething;
finally
  obj.Free;
end;

Вы абсолютно не используете try/except для этого, хотя это распространенная ошибка,Это для обработки исключений, которые отличаются от гарантии завершения.

Когда вам нужно работать с несколькими неуправляемыми ресурсами в одной функции, вы можете вкладывать свои блоки try/finally.Когда вложение глубоко, это может быть грязно.Некоторые идеи для решения этой проблемы можно найти здесь: Как избежать вложенных блоков try ... finally в Delphi

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...