情况
我将写一个类,构造函数是我自己定制的,因为我需要初始化一些值。这是我目前为止写的代码:
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;
正如你在这里看到的,我的构造函数有错误的参数,因为第二个参数是负的。我也不能理解(根据我的构造函数的代码)finally中的a.Free
是否真的需要,因为当构造函数引发异常时,析构函数被调用。
我想在try-finally块中包含a := TCombinatorio.Create(5,-2);
来避免这个问题,但我不确定。你怎么想?
4条答案
按热度按时间hmtdttj41#
你的代码是绝对正确的。从构造函数中引发异常是非常值得尊敬的。正如你所知道的,析构函数被调用了。
您询问以下代码:
你担心
Free
会在对象已经被销毁之后被调用。这是不可能发生的。如果在构造函数中引发异常,那么它会沿着调用堆栈向上传播。这发生在try
块开始之前,因此finally
块不会执行。实际上,对a
的赋值不会发生。把造物移到
try
里面将会是灾难性的,事实上这是一个非常常见的错误。现在如果一个异常被引发,那么
Free
被调用,但是在什么上呢?变量a
没有被初始化。即使它被初始化了,它也没有被初始化,这仍然是一个double free。j9per5c42#
首先可以在构造函数中引发异常,是的,它确实调用了析构函数。你展示的代码是好的。但是我认为你误解了你的代码的作用。把构造函数放在try finally块中是错误的。我认为你忽略了一点,如果你的构造函数失败,
try...finally
块永远不会被执行,所以free也不会被执行。如果构造函数不成功,就不应该调用free,这就是为什么不应该将构造函数放在try...finally
块中。rsaldnfx3#
首先我要说的是,你不能避免构造函数中的异常,所以它不可能是一个反模式。如果你检查 Delphi 源代码,你会发现构造函数中出现异常的地方很多。例如
你唯一需要知道的是,如果异常从构造函数中逸出, Delphi 会自动调用 * 析构函数 *。实际上,这意味着你的 * 析构函数 * 可能会在一个部分构造的对象上执行,正确编写 * 析构函数 * 是你的责任。请参阅TObject.Destroy文档,并特别注意下面的引文:
**注意:**如果例外状况逸出建构函式,则会呼叫解构函式来终结无法完全初始化的部分建构对象执行严修。因此,解构函式应该在尝试释放配置资源(例如控制代码)之前,先检查它们是否确实配置,因为它们的值可能是零。
PS一般来说,你应该假设每一行代码都可能引发一个异常,但是请不要偏执;)
tkclm6bt4#
在这种情况下,我通常会添加检查数据的方法:
诸多优势:
1.构造函数中没有异常。它只是简单地将其参数复制到类内字段。
1.不需要部分创建类的特殊析构函数。
1.代码简单性。