Item 39. 异常安全之函数(Exception Safe Functions)

王朝other·作者佚名  2006-01-09
宽屏版  字体: |||超大  

Item 39. Exception Safe Functions

编写异常安全代码的难点不在于抛出和捕获异常,而是在于抛出和捕获之间要做的事情。当异常从抛出

到达捕获语句的过程中,这期间执行的函数在弹栈前需要清理它所使用的任何资源。通常,这就需要片

刻的思考以及一些常识。

以String的赋值操作为例:

String &String::operator =( const char *str ) {

if( !str ) str = "";

char *tmp = strcpy( new char[ strlen(str)+1 ], str );

delete [] s_;

s_ = tmp;

return *this;

}

char *tmp 这个中间变量似乎有点多余,我们“可以”写成这样:

String &String::operator =( const char *str ) {

delete [] s_;

if( !str ) str = "";

s_ = strcpy( new char[ strlen(str)+1 ], str );

return *this;

}

果真如此吗?

delete [] 根据约定可以保证不抛出异常,然而new[]可能抛出异常。在未知新的内存是否分配成功的

时候,我们却把s_的内存释放掉了。于是,String对象处于一个bad state。

Herb Sutter 告诉我们在这种情况下应该这样处理:首先在不改变重要状态的一边处理那些能够引发异

常的操作,而后用不能引发异常的操作结束整个过程(First do anything that could cause an

exception "off to the side" without changing important state, and then use operations that

can't throw an exception to finish up.)。

再看一例:

错误的写法:

void Button::setAction( const Action *newAction ) {

delete action_; // change state!

action_ = newAction->clone(); // then maybe throw?

}

繁琐的写法:

void Button::setAction( const Action *newAction ) {

delete action_;

try {

action_ = newAction->clone();

}

catch( ... ) {

action_ = 0;

throw;

}

}

简单正确的写法:

void Button::setAction( const Action *newAction ) {

Action *temp = newAction->clone(); // off to the side...

delete action_; // then change state!

action_ = temp;

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
© 2005- 王朝网络 版权所有