C++ 最佳实践:按值抛出,按const引用捕获
示例
通常,按值(而不是按指针)但由(常量)引用捕获可认为是一种好习惯。
try {
// throw new std::runtime_error("Error!"); //不要这样!
//这将创建一个异常对象
//在堆上,将需要您抓住
//指针并自己管理内存。这个可以
//导致内存泄漏!
throw std::runtime_error("Error!");
} catch (const std::runtime_error& e) {
std::cout << e.what() << std::endl;
}引用捕获是一种好习惯的原因之一是,它消除了在传递到捕获块(或传播到其他捕获块)时重建对象的需求。通过引用捕获还可以对异常进行多态处理,并避免对象切片。但是,如果要抛出异常(例如throwe;,请参见下面的示例),则仍然可以获取对象切片,因为throwe;无论声明什么类型,该语句都会复制该异常:
#include <iostream>
struct BaseException {
virtual const char* what() const { return "BaseException"; }
};
struct DerivedException : BaseException {
// "virtual" keyword is optional here
virtual const char* what() const { return "DerivedException"; }
};
int main(int argc, char** argv) {
try {
try {
throw DerivedException();
} catch (const BaseException& e) {
std::cout << "第一个捕获块: " << e.what() << std::endl;
// Output ==> 第一个捕获块: DerivedException
throw e; //这会将异常更改为BaseException
//而不是原始的DerivedException!
}
} catch (const BaseException& e) {
std::cout << "第二个捕获块: " << e.what() << std::endl;
// Output ==> 第二个捕获块: BaseException
}
return 0;
}如果您确定不做任何更改异常的操作(例如添加信息或修改消息),则按const引用进行捕获可以使编译器进行优化并提高性能。但这仍可能导致对象拼接(如上例所示)。
警告:当心不要在catch块中引发意外的异常,尤其是与分配额外的内存或资源有关的异常。例如,由于在复制异常字符串时内存耗尽,可能会构造logic_error,runtime_error或它们的子类抛出bad_alloc异常,在设置了各自的异常掩码的日志记录期间可能会抛出I/O流,等等。