53

我发现捕获异常有三种方式,有什么区别?

1)按价值捕获;

2) 通过引用捕获;

3) 通过指针捕捉;

我只知道按值捕获会调用对象的两个副本,按引用捕获会调用一个。那么如何通过指针捕获呢?何时使用指针捕获?除了抛出一个对象,我可以像这样抛出一个指向对象的指针吗?

class A {}

void f() {

  A *p = new A();
        throw p;


}
4

5 回答 5

88

推荐的方法是按值抛出并按引用捕获

您的示例代码会抛出一个指针,这是一个坏主意,因为您必须在 catch 站点管理内存。

如果您真的觉得应该抛出一个指针,请使用智能指针,例如shared_ptr.

无论如何,Herb Sutter 和 Alexei Alexandrescu 在他们的 C++ 编码标准一书中很好地解释了这一点,我对此进行了解释。

请参阅C++ 编码标准:按值抛出,按引用捕获

于 2010-01-07T19:30:37.000 回答
17

Catch 遵循正常的赋值兼容规则,即如果你抛出一个值,你可以将它作为值或引用捕获,但不能作为指针;如果你抛出一个指针,你只能将它作为一个指针(或对指针的引用......)来捕获。

但是抛出指针并没有真正的意义,它只会引起内存管理的头痛。因此,您通常应该遵循Gregory 解释的按值抛出、按引用捕获的规则。

于 2010-01-07T19:41:16.537 回答
5

Microsoft 的 MFC 使用 catch by pointer,但我认为这是为了在正确实现 try 和 catch 之前与编译器兼容;最初他们使用 TRY 和 CATCH 宏来模拟它。每个异常都派生自 CException,它有一个方法来确定是否需要删除对象。

对于任何现代异常设计,我都不建议这样做。通过引用捕获是要走的路。

于 2010-01-07T19:43:43.977 回答
3

虽然基本上可以抛出任何类型的任何对象,但这样做几乎没有(如果有的话)。动态分配主要在对象需要有生命周期而不适合自动分配时很有用——即您希望它的生命周期独立于正常程序范围。

然而,在异常对象的情况下,这并没有多大意义。异常对象通常仅在异常处理程序内部使用,并且您显然希望在退出该异常的(最后一个)处理程序时将其销毁。

还有一个事实是,您通常希望保持异常处理代码相当简单。例如,如果您尝试报告空闲存储/堆已用尽或损坏,则尝试将异常对象从该用尽/损坏的免费存储/堆中分配出来通常不会很好地工作......

于 2010-01-07T19:50:41.887 回答
1

通过指针捕获/抛出异常并不是一个很好的场景。C++ 语义允许它,但它并不是非常有用,因为大多数时候你会抛出一个临时异常或字符串对象。

但是,一些库(我相信 Boost.Graph 会这样做)使用 throw 将返回值从深度递归函数传递回调用者;在这种情况下,返回值可能是一个指针,所以抛出一个指针是有意义的。

于 2010-01-07T19:36:24.923 回答