문제

하이 가장 좋은 방법은 무엇입을 중첩된 try&마지막으로 문 delphi?

var cds1  : TClientDataSet;
    cds2  : TClientDataSet;
    cds3  : TClientDataSet;
    cds4  : TClientDataSet;
begin
  cds1      := TClientDataSet.Create(application );
  try
    cds2      := TClientDataSet.Create(application );
    try
      cds3      := TClientDataSet.Create(application );
      try
        cds4      := TClientDataSet.Create(application );
        try
        ///////////////////////////////////////////////////////////////////////
        ///      DO WHAT NEEDS TO BE DONE
        ///////////////////////////////////////////////////////////////////////
        finally
          cds4.free;
        end;

      finally
        cds3.free;
      end;
    finally
      cds2.free;
    end;
  finally
    cds1.free;
  end;
end;

제안할 수 있습니다 더 나은 방법을 이?

도움이 되었습니까?

해결책

다음은 어떻습니까 :

var cds1  : TClientDataSet;
    cds2  : TClientDataSet;
    cds3  : TClientDataSet;
    cds4  : TClientDataSet;
begin
  cds1      := Nil;
  cds2      := Nil;
  cds3      := Nil;
  cds4      := Nil;
  try
    cds1      := TClientDataSet.Create(nil);
    cds2      := TClientDataSet.Create(nil);
    cds3      := TClientDataSet.Create(nil);
    cds4      := TClientDataSet.Create(nil);
    ///////////////////////////////////////////////////////////////////////
    ///      DO WHAT NEEDS TO BE DONE
    ///////////////////////////////////////////////////////////////////////
  finally
    freeandnil(cds4);
    freeandnil(cds3);
    freeandnil(cds2);
    freeandnil(Cds1);
  end;
end;

이것은 그것을 컴팩트하게 유지하고 만들어진 인스턴스를 자유롭게하려고 시도합니다. 실패는 마침내로 떨어지고 제공 한 예제에서 모든 정리를 수행하기 때문에 둥지를 수행 할 필요가 없습니다.

개인적으로 나는 같은 방법으로 둥지를 틀려고 노력합니다 ... 시도/시도/제외/최종 시나리오는 예외입니다. 내가 둥지를 틀어야한다면, 나에게 다른 방법 호출로 리팩토링을 생각하기에 좋은시기입니다.

편집하다 댓글 덕분에 조금 정리했습니다 MGHIE 그리고 Utku.

편집하다 이 예제에서는 필요하지 않으므로 객체 생성을 응용 프로그램을 참조하지 않도록 변경했습니다.

다른 팁

나는 다음과 같은 것을 사용할 것입니다.

var
  Safe: IObjectSafe;
  cds1 : TClientDataSet;
  cds2 : TClientDataSet;
  cds3 : TClientDataSet;
  cds4 : TClientDataSet;
begin
  Safe := ObjectSafe;
  cds1 := Safe.Guard(TClientDataSet.Create(nil)) as TClientDataSet;
  cds2 := Safe.Guard(TClientDataSet.Create(nil)) as TClientDataSet;
  cds3 := Safe.Guard(TClientDataSet.Create(nil)) as TClientDataSet;
  cds4 := Safe.Guard(TClientDataSet.Create(nil)) as TClientDataSet;
  ///////////////////////////////////////////////////////////////////////
  ///      DO WHAT NEEDS TO BE DONE
  ///////////////////////////////////////////////////////////////////////

  // if Safe goes out of scope it will be freed and in turn free all guarded objects
end;

인터페이스의 구현은 참조하십시오 이것 기사이지만 쉽게 비슷한 것을 만들 수 있습니다.

편집하다:

방금 링크 된 기사에서 Guard ()가 절차라는 것을 알았습니다. 내 자신의 코드에서 나는 Tobject를 반환하는 Guard () 함수를 과부하 시켰으며, 위의 샘플 코드는 비슷한 것을 가정합니다. 물론 제네릭을 사용하면 훨씬 더 나은 코드가 가능합니다 ...

편집 2 :

내 코드에서 마침내 완전히 제거 된 이유가 궁금하다면 : 메모리 누출 가능성 (소멸자가 예외를 제외 할 때) 또는 액세스 위반 가능성을 도입하지 않고 중첩 블록을 제거하는 것은 불가능합니다. 따라서 도우미 클래스를 사용하고 인터페이스의 참조 계산을 완전히 인수하는 것이 가장 좋습니다. 도우미 클래스는 일부 소멸자 중 일부가 예외를 제기하더라도 모든 대상을 보호 할 수 있습니다.

중첩 시도가없는 코드의 또 다른 변형이 있습니다 ... 마침내 나에게 일어난 일이 일어났습니다. NIL로 설정된 생성자의 AOWNER 매개 변수로 구성 요소를 만들지 않으면 VCL이 무료로 제공하는 평생 관리를 사용할 수 있습니다.

var
  cds1: TClientDataSet;
  cds2: TClientDataSet;
  cds3: TClientDataSet;
  cds4: TClientDataSet;
begin
  cds1 := TClientDataSet.Create(nil);
  try
    // let cds1 own the other components so they need not be freed manually
    cds2 := TClientDataSet.Create(cds1);
    cds3 := TClientDataSet.Create(cds1);
    cds4 := TClientDataSet.Create(cds1);

    ///////////////////////////////////////////////////////////////////////
    ///      DO WHAT NEEDS TO BE DONE
    ///////////////////////////////////////////////////////////////////////

  finally
    cds1.Free;
  end;
end;

나는 작은 코드를 큰 신자입니다 (너무 난독 화되지 않은 경우).

이 (IMO) 못생긴 경로 (프리가 필요한지 알기 위해 NIL에 대한 초기화로 그룹 취급)를 원한다면, 적어도 파괴자 중 하나에서 예외가 나머지 부분을 해방시키는 것을 방지하지 않도록 보장해야합니다. 당신의 대상.
같은 것 :

function SafeFreeAndNil(AnObject: TObject): Boolean;
begin
  try
    FreeAndNil(AnObject);
    Result :=  True;
  except
    Result := False;
  end;
end;

var cds1  : TClientDataSet;
    cds2  : TClientDataSet;
    IsOK1 : Boolean;
    IsOK2 : Boolean;
begin
  cds1      := Nil;
  cds2      := Nil; 
 try
    cds1      := TClientDataSet.Create(nil);
    cds2      := TClientDataSet.Create(nil);    
    ///////////////////////////////////////////////////////////////////////
    ///      DO WHAT NEEDS TO BE DONE
    ///////////////////////////////////////////////////////////////////////
  finally
    IsOk2 := SafeFreeAndNil(cds2);    // an error in freeing cds2 won't stop execution
    IsOK1 := SafeFreeAndNil(Cds1);
    if not(IsOk1 and IsOk2) then
      raise EWhatever....
  end;
end;

좋은 비디오가 있습니다 생성자 및 소멸자의 예외

그것은 다음과 같은 몇 가지 좋은 예를 보여줍니다.

var cds1  : TClientDataSet;
    cds2  : TClientDataSet;
begin
  cds1      := Nil;
  cds2      := Nil; 
 try
    cds1      := TClientDataSet.Create(nil);
    cds2      := TClientDataSet.Create(nil);    
    ///////////////////////////////////////////////////////////////////////
    ///      DO WHAT NEEDS TO BE DONE
    ///////////////////////////////////////////////////////////////////////
  finally
    freeandnil(cds2);    //// what has if there in an error in the destructor of cds2
    freeandnil(Cds1);
  end;
end;

CDS2의 파괴자에 오류가 있다면 무엇이 있습니까?

CDS1은 파괴되지 않습니다

편집하다

또 다른 좋은 자원은 다음과 같습니다.

Jim McKeeth 훌륭한 비디오 지연된 예외 처리 코드 범위 III에서 그는 마지막으로 블록의 예외를 처리하는 문제에 대해 이야기했습니다.

@mghie:델파이어 스택 할당 개체:

type
  TMyObject = object
  private
    FSomeField: PInteger;
  public
    constructor Init;
    destructor Done; override;
  end;

constructor TMyObject.Init;
begin
  inherited Init;
  New(FSomeField);
end;

destructor TMyObject.Done;
begin
  Dispose(FSomeField);
  inherited Done;
end;

var
  MyObject: TMyObject;

begin
  MyObject.Init;
  /// ...
end;

불행하게도,위의 예를 보여줍니다:스택당 개체지 않는 메모리 누수를 방지합니다..

그래서 이것은 여전히 필요한 전화를 소멸자는 다음과 같다:

var
  MyObject: TMyObject;

begin
  MyObject.Init;
  try
    /// ...
  finally
    MyObject.Done;
  end;
end;

OK,나는 그것을 승인한다,이것은 매우 거의 주제,하지만 나는 생각에서 흥미로운 일이 될 수 있습니다 이 상황 때문에 스택 할당 개체었으로 언급된 솔루션(는 그들은하지 않는 경우는 없이 자동 소멸자출).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top