catch exceptions
写一个catch子句时必须指明异常对象是如何传递到这个子句来的,三种方式:
- by pointer
- by value
- by reference
接下来比较它们使用时会出现的问题,以说明最好的选择是by reference。
catch by pointer
- 无需复制对象,所以效率高;
- 如果未使用全局或静态对象,则可能出现“我捕捉到一个指针,它却指向一个已经不存在的对象”的问题;
- 4个标准异常:bad_malloc(当operator new无法满足内存需求时被抛出),bad_cast(当对一个reference施行dynamic_cast失败时发出),bad_typeid(当dynamic_cast被实施于一个null指针时发出),bad_exception(适用于未预期的异常情况) ——都是对象,不是指向对象的指针。
catch by value
- 解决上述问题;
- 需要复制两次;
- 会引起切割(slicing)问题:
派生类的异常对象被捕捉,并且被视为基类的异常对象,那么派生类就被切割掉了,如:
class exception //标准异常类
{
public:
virtual const char* what() throw();
};
class runtime_error://标准异常类
public exception{...}
class Validation_error //重新定义的异常类
public exception
{
public:
virtual const char* what() throw();
}
void someFunction()
{
...
if(失败)
throw Validation_error();
}
void doSomething()
{
try{
someFunction();
}
catch(exception ex)
{
cerr << ex.what(); //调用的exception::what
} //而不是Validation_error::what
}
调用的是基类的what函数——即使抛出的异常属于Validation_error类型,而Validation_error重新定义了虚函数。
catch by reference
- 解决上述问题:即不会发生对象删除的问题、避开异常对象的切割问题;
- 异常对象只会被复制一次。
void doSomething()
{
try{
someFunction();
}
catch(exception& ex) //catch by reference
{
cerr << ex.what();
//调用的是Validation_error::what
// 而非exception::what
}
}
总结
最佳的捕捉异常方式:catch by reference。
(catch子句内增加一个&符号)