状况
我打算写一个类,构造函数是我自己创建的一个,因为我需要初始化一些值。这是我到目前为止编写的代码:
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);
以避免问题,但我不确定。你觉得怎么样?
答案 0 :(得分:18)
您的代码绝对正确无误。提高构造函数的异常是完全可敬的。如你所知,析构函数被调用。
你问这个代码:
a := TCombinatorio.Create(5,-2);
try
//some code
finally
a.Free;
end;
您担心在对象被销毁后将调用Free
。这不可能发生。如果在构造函数中引发异常,则它会向上传播调用堆栈。这发生在try
块开始之前,因此finally
块不会执行。实际上,a
的任务不会发生。
在try
内移动创作将是灾难性的,实际上是一个非常常见的错误。假设你这样做了:
// WARNING THIS CODE IS DEFECTIVE
try
a := TCombinatorio.Create(5,-2);
//some code
finally
a.Free;
end;
现在如果引发异常,则会调用Free
但是在什么?变量a
未初始化。即使它是,它不是,它仍然是一个双重自由。
答案 1 :(得分:4)
好的,首先你可以在构造函数中引发异常,是的,它确实会调用析构函数。你展示的代码很好。但我认为你误解了你的代码所做的事情。并将构造函数置于try finally块中是错误的。我认为您缺少的一点是,如果您的构造函数失败,public static String[] bilgiler;
stringArray = parseJson(result);
sayaca=(Integer)stringArray.length;
tvData2.setText("Burası arrayden geliyor :" + stringArray[1].toString() + sayaca );
sayacim = sayaca;
bilgiler = new String[sayacim];
bilgiler = stringArray;
setupToolbar();
initNavigationDrawer();
块永远不会被执行,因此不执行free。如果构造函数不成功,则不应该调用free,这就是不将构造函数放在try...finally
块中的原因。
答案 2 :(得分:3)
首先,我要说你不能避免构造函数中的异常,因此它不能成为反模式。如果你检查Delphi源代码,你会发现在构造函数中引发异常的地方数量。例如
constructor TCustomForm.Create(AOwner: TComponent);
begin
// ... skipped some lines
if not InitInheritedComponent(Self, TForm) then
raise EResNotFound.CreateFmt(SResNotFound, [ClassName]);
你唯一应该知道的是,如果异常从构造函数中逃脱,Delphi将自动调用析构函数。实际上,这意味着您的析构函数可以在部分构造的对象上执行,您有责任正确编写析构函数。请参阅TObject.Destroy文档,并特别注意以下引用:
注意:如果异常从构造函数中转义,则会调用析构函数来销毁部分构造的对象实例 无法完全初始化。因此,析构函数应该检查 实际分配了分配资源(如句柄) 在尝试释放它们之前,因为它们的值可能为零。
PS一般来说,您应该假设每行代码可能引发异常,但请不要成为偏执狂;)