分享
 
 
 

再谈异常——谈C++与Object Pascal中的构造函数与异常

王朝delphi·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

作者:Nicrosoft(nicrosoft@sunistudio.com) 2001.9.15

个人主页:http://www.sunistudio.com/nicrosoft/

东日文档:http://www.sunistudio.com/asp/sunidoc.asp

我们知道,类的构造函数是没有返回值的,如果构造函数构造对象失败,不可能依靠返回错误代

码。那么,在程序中如何标识构造函数的失败呢?最“标准”的方法就是:抛出一个异常。

构造函数失败,意味着对象的构造失败,那么抛出异常之后,这个“半死不活”的对象会被如何

处理呢?这就是本文的主题。

在C++中,构造函数抛出异常后,析构函数不会被调用。这是合理的,因为此时对象并没有被完整

构造。也就是说,如果构造函数已经做了一些诸如分配内存、打开文件等操作的话,那么类需要有自

己的成员来记住做过哪些动作。在C++中,经典的解决方案是使用STL的标准类auto_ptr,这在每一本

经典C++著作中都有介绍,我在这里就不多说了。在这里,我想再介绍一种“非常规”的方式,其思想

就是避免在构造函数中抛出异常。我们可以在类中增加一个 Init(); 以及 UnInit();成员函数用于进

行容易产生错误的资源分配工作,而真正的构造函数中先将所有成员置为NULL,然后调用 Init(); 并

判断其返回值(或者捕捉 Init()抛出的异常),如果Init();失败了,则在构造函数中调用 UnInit

(); 并设置一个标志位表明构造失败。UnInit()中按照成员是否为NULL进行资源的释放工作。示例代

码如下:

class A

{

private:

char* str;

int failed;

public:

A();

~A();

int Init();

int UnInit();

int Failed();

};

A::A()

{

str = NULL;

try

{

Init();

failed = 0;

}

catch(...)

{

failed = 1;

UnInit();

}

}

A::~A()

{

UnInit();

}

int A::Init()

{

str = new char[10];

strcpy(str, "ABCDEFGHI");

throw 10;

return 1;

}

int A::UnInit()

{

if (!str)

{

delete []str;

str = NULL;

}

printf("Free Resource\n");

return 1;

}

int A::Failed()

{

return failed;

}

int main(int argc, char* argv[])

{

A* a = new A;

if ( a->Failed() )

printf("failed\n");

else

printf("succeeded\n");

delete a;

getchar();

return 0;

}

你会发现,在int A::Init()中包含了throw 10;的代码(产生一个异常,模拟错误的发生),执

行结果是:

Free Resource

failed

Free Resource

虽然 UnInit();被调用了两次,但是由于UnInit();中做了判断(if (!str)),因此不会发生错

误。而如果没有发生异常(去掉 int A::Init()中的throw 10;代码),执行结果是:

Succeeded

Free Resource

和正常的流程没有任何区别。

在Object Pascal(Delphi/VCL)中,这个问题就变得非常的简单了,因为 OP 对构造函数的异常

的处理与C++不同,在Create时抛出异常后,编译器会自动调用析构函数Destroy,并且会判断哪些资

源被分配了,实行自动回收。因此,其代码也变得非常简洁,如下:

type

A = class

private

str : PChar;

public

constructor Create();

destructor Destroy(); override;

end;

constructor A.Create();

begin

str := StrAlloc(10);

StrCopy(str, 'ABCDEFGHI');

raise Exception.Create('error');

end;

destructor A.Destroy();

begin

StrDispose(str);

WriteLn('Free Resource');

end;

var oa : A;

i : integer;

begin

try

oa := A.Create();

WriteLn('Succeeded');

oa.Free();

except

oa := nil;

WriteLn('Failed');

end;

Read(i);

end.

在这段代码中,如果构造函数抛出异常(即Create中含有raise Exception.Create

('error');),执行的结果是:

Free Resource

Failed

此时的“Free Resource”输出是由编译器自动调用析构函数所产生的。而如果构造函数正常返回

(即不抛出异常),则执行结果是:

Succeeded

Free Resource

此时的“Free Resource”输出是由 oa.Free()的调用产生的。

综上,C++与Object Pascal对于构造函数抛出异常后的不同处理方式,其实正是两种语言的设计

思想的体现。C++秉承C的风格,注重效率,一切交给程序员来掌握,编译器不作多余动作。Object

Pascal继承Pascal的风格,注重程序的美学意义(不可否认,Pascal代码是全世界最优美的代码),

编译器帮助程序员完成复杂的工作。两种语言都有存在的理由,都有存在的必要!而掌握它们之间的

差别,能让你更好地控制它们,达到自由的理想王国。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有