systems - delphi method



델파이는 생성자에서 예외를 발생시킵니다. (2)

귀하의 코드는 정확하고 정확합니다. 생성자에서 예외를 발생시키는 것은 완벽하게 존중할 수 있습니다. 아시다시피 소멸자가 호출됩니다.

이 코드에 대해 물어보십시오 :

a := TCombinatorio.Create(5,-2);
try
  //some code
finally
  a.Free; 
end;

개체가 이미 파괴 된 후에 Free 가 호출 될지 걱정됩니다. 그것은 일어날 수 없다. 예외가 생성자에서 발생하면 호출 스택을 전파합니다. 이는 try 블록이 시작되기 전에 발생하기 때문에 finally 블록은 실행되지 않습니다. 실제로에 대한 할당은 발생하지 않습니다.

try 안에 창조물을 옮기는 것은 재앙이되며 실제로는 매우 흔한 실수입니다. 당신이 그렇게했다고 가정 해보십시오 :

// WARNING THIS CODE IS DEFECTIVE 
try
  a := TCombinatorio.Create(5,-2);
  //some code
finally
  a.Free; 
end;

이제 예외가 발생하면 Free 가 호출되지만, 무엇이 필요합니까? 변수 a 는 초기화되지 않습니다. 비록 그것이 아니더라도, 그것은 여전히 ​​두 배의 자유가 될 것입니다.

상태

클래스를 작성하려고하는데 생성자는 일부 값을 초기화해야하기 때문에 내가 만든 맞춤형 클래스입니다. 이것은 지금까지 작성한 코드입니다.

type
 TCombinatorio = class(TObject)
  private
   valN, valK: integer;
   result: double;
  public
   property K: integer read valK;
   property N: integer read valN;
   constructor Create(valN: integer; valK: integer);
 end;

constructor TCombinatorio.Create(valN: Integer; valK: Integer);
begin
  inherited Create;
   Self.valN := valN;
   Self.valK := valK;

  if ((valN < 0) or (valK < 0)) then
   begin
    raise Exception.Create('N and K must be >= 0');
   end;

end;

몇 가지 수학 계산을 할 것이므로 음수를 피할 필요가 있습니다.

의문

그런 식으로 생성자에서 예외를 호출 할 수 있습니까? 이 방법으로 코드를 실행하고 있습니다.

procedure TForm1.Button1Click(Sender: TObject);
var a: TCombinatorio; 
    b: string;   
begin

 a := TCombinatorio.Create(5,-2);

 try
  //some code
 finally
  a.Free; 
 end;

end;

여기서 볼 수 있듯이 두 번째 매개 변수가 잘못된 것이므로 생성자에 대한 잘못된 매개 변수가 있습니다. 나는 또한 생성자의 코드에 따라 이해할 수 없다. 왜냐하면 생성자가 예외를 발생시킬 때 소멸자가 호출되기 때문에 a.Free 가 필요하다.

나는 a := TCombinatorio.Create(5,-2); 를 포함 a := TCombinatorio.Create(5,-2); 생각했다 a := TCombinatorio.Create(5,-2); 문제를 피하기 위해 try-finally 블록 안에 있지만 확실하지 않습니다. 어떻게 생각해?


우선 나는 생성자에서 예외를 피할 수 없으므로 안티 패턴이 될 수 없다고 말할 것입니다. Delphi 소스 코드를 확인하면 생성자에서 예외가 발생한 곳을 찾을 수 있습니다. 예를 들어

constructor TCustomForm.Create(AOwner: TComponent);
begin
  // ... skipped some lines
        if not InitInheritedComponent(Self, TForm) then
          raise EResNotFound.CreateFmt(SResNotFound, [ClassName]);

당신이 알아야 할 유일한 것은 예외가 생성자에서 빠져 나면 Delphi가 자동으로 소멸자를 호출한다는 것입니다. 실제로 그것은 소멸자 가 부분적으로 생성 된 객체에서 실행될 수 있으며 소멸자를 올바르게 작성해야 할 책임이 있음을 의미합니다. TObject.Destroy 문서를 참조하고 아래 인용문에 특히주의하십시오.

참고 : 예외가 생성자에서 이스케이프되면 소멸자가 호출되어 완전히 초기화하지 못한 부분적으로 생성 된 객체 인스턴스가 삭제됩니다. 따라서 소멸자는 핸들과 같은 할당 된 리소스가 실제로 할당되었는지 확인해야합니다. 즉, 값이 0 일 수 있기 때문입니다.

추신 : 일반적 으로 코드의 각 라인이 예외를 발생시킬 수 있다고 생각해야하지만, 편집증에 빠지지 마십시오.)