我发现有三种方法可以捕获异常,它们有什么不同?
1)值捕获;
2)引用捕获;
3)指针捕获;
我只知道值捕获会调用对象的两个副本,引用捕获只会调用一个。那么指针捕获呢?何时使用指针捕获?除了抛出一个对象之外,我能像这样抛出一个指向对象的指针吗?
class A {}
void f() {
A *p = new A();
throw p;
}
我发现有三种方法可以捕获异常,它们有什么不同?
1)值捕获;
2)引用捕获;
3)指针捕获;
我只知道值捕获会调用对象的两个副本,引用捕获只会调用一个。那么指针捕获呢?何时使用指针捕获?除了抛出一个对象之外,我能像这样抛出一个指向对象的指针吗?
class A {}
void f() {
A *p = new A();
throw p;
}
推荐的方法是按值抛出异常,按引用捕获异常。
你的示例代码抛出指针是个坏主意,因为你必须在捕获时管理内存。
如果你真的想抛出指针,请使用智能指针,例如shared_ptr
。
无论如何,Herb Sutter和Alexei Alexandrescu在他们的C++编程标准书中很好地解释了这一点,我进行了概述。
const std::runtime_error err; throw err;
。我是否正确地认为,实际上不会通过引用捕获它(从const std::runtime_error&
到std::runtime_error&
没有转换)?因此,这将被运行时捕获,并可能导致程序崩溃。我是对的吗? - the swinestd::exception
构造函数中复制带有异常描述的std::string
。但是如果复制失败,我猜测会抛出一个无原因的std::bad_alloc
异常。或者可能会导致无限递归 :)。想得很周到。 - the swineCatch 遵循常规的赋值兼容性规则,也就是说,如果你抛出一个值,你可以将其作为值或引用来 catch,但不能作为指针;如果你抛出一个指针,你只能将其作为指针(或指针的引用)来 catch ......
但抛出指针实际上没有什么意义,它只会带来内存管理方面的麻烦。因此,通常应遵循“按值抛出,按引用 catch”的规则,正如 Gregory 所解释的那样。
Microsoft的MFC使用指针捕获,但我认为这是为了与try和catch正确实现之前的编译器兼容性;最初他们使用TRY和CATCH宏来模拟它。每个异常都派生自CException,它有一个方法来确定对象是否需要被删除。
我不建议在任何现代异常设计中使用这种方式。通过引用捕获是正确的方式。
没有一个好的场景可以通过指针捕获/抛出异常。 C++语义允许它,但它并不是非常有用,因为大多数时候你会抛出一个临时异常或字符串对象。
然而,一些库(我相信Boost.Graph就是这样做的)使用throw将返回值从深度递归函数传递回调用者;在这种情况下,返回值可能是一个指针,因此抛出指针是有意义的。