127

在查看一些代码时,我偶然发现:

throw /*-->*/new std::exception ("//...

我一直认为你不需要/你不应该new在这里使用。
正确的方法是什么,都可以,如果可以,有什么区别吗?

顺便说一句,我在使用 PowerShell boost 库“grepping”时所看到的从不使用throw new.

PS 我还发现了一些使用throw gcnew. 那样可以么?

4

5 回答 5

98

抛出和捕获异常的常规方法是抛出一个异常对象并通过引用(通常是const引用)来捕获它。C++ 语言要求编译器生成适当的代码来构造异常对象,并在适当的时候对其进行适当的清理。

抛出指向动态分配对象的指针绝不是一个好主意。异常应该使您能够在面对错误条件时编写更健壮的代码。如果您以常规方式抛出异常对象,则可以确定它是否被命名正确类型的 catch 子句捕获,是否被 a 捕获,catch (...)然后是否重新抛出它,它将在适当的时间正确销毁。(唯一的例外是,如果它根本没有被捕获,但无论你怎么看,这都是不可恢复的情况。)

如果你抛出一个指向动态分配对象的指针,你必须确保无论调用堆栈在你想要抛出异常的时候是什么样的,都有一个 catch 块,它命名了正确的指针类型并具有适当的delete调用。catch (...)除非该块重新抛出异常,然后该异常被另一个正确处理异常的 catch 块捕获,否则您的异常决不能被捕获。

实际上,这意味着您已经采用了异常处理功能,该功能应该可以更轻松地编写健壮的代码,并且很难编写在所有情况下都正确的代码。这撇开了一个问题,即几乎不可能充当不期望此功能的客户端代码的库代码。

于 2012-06-09T20:44:23.153 回答
34

new抛出异常时无需使用。

写吧:

throw yourexception(yourmessage);

并捕捉为:

catch(yourexception const & e)
{
      //your code (probably logging related code)
}

注意应该直接或间接yourexception派生。std::exception

于 2012-06-08T11:53:54.430 回答
24

如果调用new std::exception站点期望捕获一个std::exception*. 但是没有人会期望捕获指向异常的指针。即使您记录了您的函数所做的事情并且人们阅读了文档,他们仍然很容易忘记并尝试捕获对std::exception对象的引用。

于 2012-06-08T11:58:52.303 回答
9

C++ FAQ 对此进行了很好的讨论:

  1. https://isocpp.org/wiki/faq/exceptions#what-to-catch
  2. https://isocpp.org/wiki/faq/exceptions#catch-by-ptr-in-mfc

基本上“除非有充分的理由不这样做,否则按引用捕获。避免按值捕获,因为这会导致生成副本,并且副本的行为可能与抛出的行为不同。只有在非常特殊的情况下才应该通过指针捕获。 "

于 2012-06-08T12:04:34.097 回答
2

运算符 new 不能保证它永远不会引发异常。出于这个原因,使用它来引发“有效”(预期)异常会产生无法保证不会崩溃的代码。由于一次可能只有一个异常,并且您的程序试图在捕获其中任何一个之前抛出两个异常,因此实现可以做的最好的事情是立即中止您的程序,例如通过调用 std::terminate。

于 2019-11-29T00:14:30.080 回答