Delphi在构造函数中引发异常

Alb*_*ola 17 delphi

情况

我打算写一个类,构造函数是我自己创建的一个,因为我需要初始化一些值.这是我到目前为止编写的代码:

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;
Run Code Online (Sandbox Code Playgroud)

由于我要做一些数学计算,我需要避免负数.


我可以用这种方式在构造函数中调用异常吗?我正在以这种方式运行代码:

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

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

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

end;
Run Code Online (Sandbox Code Playgroud)

正如你在这里看到的,我的构造函数有错误的参数,因为第二个是负数.我也无法理解(根据我的构造函数的代码)是否a.Free真的需要finally内部,因为当构造函数引发异常时,析构函数被调用.

我想包括a := TCombinatorio.Create(5,-2);try-finally块内部以避免问题,但我不确定.你怎么看?

Dav*_*nan 20

你的代码绝对正确无误.提高构造函数的异常是完全可敬的.如你所知,析构函数被调用.

你问这个代码:

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

您担心Free在对象被销毁后将被调用.这不可能发生.如果在构造函数中引发异常,则它会向上传播调用堆栈.这发生在try块开始之前,因此finally块不执行.确实,任务a没有发生.

在内部移动创建try将是灾难性的,实际上是一个非常常见的错误.假设你这样做了:

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

现在如果引发异常然后Free被调用但是在什么?变量a未初始化.即使它不是,它仍然是双重自由.

  • @kludg - 如果你在构造时知道实例将无法使用,那么构造函数是引发异常imo的最佳位置.另一种方法是在使用实例时引发异常,这可能会导致有趣的调试会话以了解错误的来源.也就是说,在这种特定情况下,OP应该切换到无符号整数. (3认同)
  • @kludg:我完全不同意。请注意,与局部变量不同,引用类型的类字段(如TObject)总是用nil初始化。在析构函数中调用`myAggregatedObject.Free()`即可。但是,您应该避免在构造函数中调用虚拟方法,但这是一个完全不同的故事,不仅适用于Delphi。 (2认同)
  • @serg 在析构函数中引发异常是错误的。但它是为构造函数明确设计和支持的。你不编写析构函数来处理部分构造吗? (2认同)