Item 39. 异常安全之函数(Exception Safe Functions)
2005-04-22 15:50
405 查看
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;
}
编写异常安全代码的难点不在于抛出和捕获异常,而是在于抛出和捕获之间要做的事情。当异常从抛出
到达捕获语句的过程中,这期间执行的函数在弹栈前需要清理它所使用的任何资源。通常,这就需要片
刻的思考以及一些常识。
以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;
}
相关文章推荐
- Item 39. 异常安全之函数(Exception Safe Functions)
- Item 39. 异常安全之函数(Exception Safe Functions)
- Item 38. 异常安全之公理(Exception Safety Axioms)
- [翻译] Effective C++, 3rd Edition, Item 29: 争取 exception-safe code(异常安全代码)(下)
- Item 38. 异常安全之公理(Exception Safety Axioms)
- Item 38. 异常安全之公理(Exception Safety Axioms)
- [翻译] Effective C++, 3rd Edition, Item 29: 争取 exception-safe code(异常安全代码)(上)
- More Effective C++(条款12:了解“抛出一个异常exception”与“传递一个参数”或“调用一个虚函数”之间的差异)
- [System.OutOfMemoryException] {函数求值已禁用,因为出现内存不足异常。
- C#调用参数为函数指针的API函数 - 以SetUnhandledExceptionFilter为例编写一个全局异常处理程序
- 《Effective C++》读书笔记之item29:为“异常安全”而努力是值得的
- 异常处理——异常函数之SetUnhandledExceptionFilter(父进程处理)(2)
- ListView遍历每个Item出现NullPointerException的异常
- ListView遍历每个Item出现NullPointerException的异常
- ListView遍历每个Item出现NullPointerException的异常(转)
- C++通用构件中的异常安全 Exception-Safety in Generic Components
- 赋值运算符函数异常安全
- Item 14: 如果函数不会抛出异常就把它们声明为noexcept
- Integer.parseInt()函数 NumberFormatException异常问题
- PHP异常处理函数set_exception_handler()的用法