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

作者: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 ");
return 1;
}

int A::Failed()
{
return failed;
}

int main(int argc, char* argv[])
{
A* a = new A;
if ( a->Failed() )
printf("failed ");
else
printf("succeeded ");

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代码是全世界最优美的代码),
编译器帮助程序员完成复杂的工作。两种语言都有存在的理由,都有存在的必要!而掌握它们之间的
差别,能让你更好地控制它们,达到自由的理想王国。
数据挖掘实验室

[数据挖掘专家] [数据挖掘研究院] [数据挖掘论坛] [数据挖掘实验室]
上一篇:OPC标准—你知道吗?
下一篇:什么是"面向对象编程"(1991修订版)
最新评论共有 0 位网友发表了评论 , 查看所有评论
发表评论( 不能超过250字,需审核,请自觉遵守互联网相关政策法规。 )
匿名?
数据挖掘网站导航 数据挖掘论坛导航
  • 数据挖掘工具
  • 数据挖掘论坛
  • DataCruncher - Cognos
  • MineSet - MathSoft
  • Intelligent Miner - GainSmarts
  • Sqlserver - SAS - Clementine
  • CART - Weka - WizSoft
  • NeuroShell - ModelQuest
  • data mining tools - Darwin
  • 数据挖掘交友
  • 数据挖掘博客
  • 数据挖掘工具
  • 数据挖掘资源
  • 数据挖掘技术算法
  • 数据挖掘相关期刊、会议
  • 研究院联盟合作专区
  • 数据挖掘基础与相关技术
  • 数据挖掘厂商与就业
  • 数据挖掘研究者乐园
  • 知名厂商数据挖掘工具资料
  • 国内数据挖掘实验室
  • Foreign Data Mining Lab
  • 热点关注
  • Internet控制信息协议(ICMP)
  • 微软公司软件开发模式简介
  • http1.1
  • TCP协议规范(中文版)
  • linux端口列表
  • 语音识别进入IVR系统
  • Api函数列表——与文件相关
  • RVP:存在和即时消息传送协议(3)
  • Win32环境下动态链接库(DLL)编程原理
  • PPPInternet协议控制协议(中文版)
  • 论坛最新话题
  • Foundations of Statistical Natural Langu
  • Game Theory meet Data Mining: A Recent P
  • System Building: How does it help or hin
  • 数据挖掘与Clementine培训
  • 新手报到
  • 求 SASEM 客户流失预测分析
  • 数据挖掘工程师/搜索研究院—北京——无线
  • 数据挖掘入门介绍(如何着手数据挖掘)
  • Information Overload Survey Results
  • The INEX 2005 Workshop on Element Retrie
  • 相关资讯
  • Internet控制信息协议(ICMP)
  • 中文RFC文档远程COM选项(四)
  • Api函数列表——与文件相关
  • RVP:存在和即时消息传送协议(3)
  • 微软公司软件开发模式简介
  • MMXInstructions
  • TCP协议规范(中文版)
  • PPPInternet协议控制协议(中文版)
  • 语音识别进入IVR系统
  • http1.1
  • 数据挖掘实验室资料
  • 数据挖掘博客地址
  • 数据挖掘实验室网站地址
  • Prepare for Medicare audits by using dat
  • 注册成为SAS用户与爱好者俱乐部会员
  • 水南梅
  • 明日烟
  • 新人报道
  • 下载
  • 厦门服务器托管,450元/月—0592-5177319 高
  • 买空间送域名--0592-5177319 高静