第三章,异常

条款13 以by reference方式捕捉exceptions

by pointer

by pointer 抛出异常,不会产生复制对象,但是接收到指针后,是否应该删除指针,这成了一个哈姆雷特式的难题;如果是 throw &object; 不需要删除,但如果是throw new object;就需要删除,显然这种不确定性的设计不好;此外,C++的四个标准exceptions: bad_alloc(无法满足内存需求时抛出-8),bad_cast(对一个reference强行dynamic_cast时发出-2),bad_typeid(dynamic_cast被实施于一个null指针时发出),bad_exception(适用于未预期的异常情况-14) 全都是对象,不是对象指针,因此抛出指针与C++本身建立的惯例是有矛盾的。

by value

by value 抛出异常,会复制两次对象,并且会导致继承下的切割问题:抛出派生类对象,但是只能识别为基类型,在catch子句接收后,会丢失派生类对象中记录的成员变量,且调用的析构函数是基类的析构函数,这就是切割问题。

by reference

by reference 抛出异常,不会有“是否删除指针”和“与标准exception不一致”的问题,且只复制一次,也不会存在继承类的切割问题;

class exception {
public:
virtual const char * what() throw();//这里的throw()是异常说明符,承诺这个函数在执行过程中不会抛出任何异常,C++11后改为noexcept
//virtual const char * what() noexcept; //C++11
//noexcept: 一旦违背承诺抛出了异常,C++ 会触发强制的程序终止逻辑,执行std::unexpected()(该函数默认行为是调用 std::terminate())
//如果 throw() 里写了具体的类型,比如 throw(runtime_error),表示这个函数只能抛出括号内指定类型的异常,抛出其他类型会触发程序报错;

/*what() 函数设计为不抛异常,是为了保证:即使在处理异常的过程中(比如打印异常信息),what() 本身也不会再抛出新的异常,避免异常处理逻辑崩溃*/
...
};

class runtime_error:
public exception{ ... };

class Validation_error:
public runtime_error{
public:
virtual const char * what()throw();
//virtual const char * what() noexcept; //C++11
...
};

void someFunction()
{
...
if(a validation test fails)
{
throw Vaildation_error();
}
...
}

void doSomething()
{
try{
someFunction();
}
catch(exception& ex){

cerr<<ex.what();
...
}

}