抛出新的std :: exception vs抛出std :: exception


113

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

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

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

顺便说一句,从我用PowerShell增强库“抓取”时可以看到,从未使用过throw new

PS还发现了一些使用的CLI代码throw gcnew。那样行吗?


1
我认为throw gcnew将是有用的。如果您希望托管代码捕获异常。有人可以纠正我吗?
jpalecek 2012年

1
.Net通过指针处理异常,因此抛出gcnew是正确的做法。
塞巴斯蒂安·雷德尔

1
@SebastianRedl .Net“指针”可能不明确?尽管gcnew当然不是。 System::Exception通常是对垃圾收集堆上的托管对象的引用。我总是被gcnew迷住了System::Exception ^。当然,我也finally一直在C ++ / CLI中使用所有时间,尽管并不经常在同try一块中混用C ++异常,但我不确定为什么。

Answers:


89

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

将指针指向动态分配的对象绝不是一个好主意。异常应该使您能够在遇到错误情况时编写更强大的代码。如果以常规方式抛出异常对象,则可以确保是否通过命名正确类型的catch子句捕获该异常对象,通过a捕获该异常对象,catch (...)然后重新抛出该异常对象,该异常对象将在适当的时间正确销毁。(唯一的例外是,即使它从未被捕获,但是无论您采用哪种方式,这都是不可恢复的情况。)

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

实际上,这意味着您已经采用了异常处理功能,该功能应该使编写健壮的代码更加容易,并且使编写在所有情况下正确的代码变得非常困难。这就排除了一个问题,几乎不可能充当不会期望此功能的客户端代码的库代码。


1
“抛出异常对象”堆栈还是堆我的朋友?堆还是堆?(也许我在某个地方看过一个不好的全局示例)哦,如果是堆栈,那么合适的范围是什么?

@ebyrob:我不太确定您要问的是什么,但这听起来像是您想了解异常对象的存储和/或生存期,可以在这里回答。如果不是这样,您最好再问一个单独的问题。
CB Bailey

31

new引发异常时无需使用。

写就好了:

throw yourexception(yourmessage);

并捕获为:

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

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


7
为什么?为什么不使用new?为什么yourexceptionstd::exception
Walter

当我懒惰时(通常很奇怪)为什么不起作用throw std::exception;?g ++似乎无法编译它

7
@ebyrob:std::exception是一个类型,您不能抛出一个类型,必须抛出一个对象。所以语法应该是这样:throw std::exception();可以编译。现在,这到底有多好,是一个完全不同的问题。
Nawaz

22

new std::exception如果呼叫站点希望捕获,则抛出正确std::exception*。但是没有人会期望得到指向异常的指针。即使您的文档是函数的功能,即使人们阅读了文档,他们仍然有可能忘记并尝试捕获对std::exception对象的引用。


27
new std::exception仅当调用站点希望捕获指针并且希望接管分配异常的管理并且永远不会在任何情况下被未明确捕获的函数调用函数时,抛出才是正确的正确的指针(catch(...)或根本没有处理),否则将发生对象泄漏。简而言之,这可以近似为“从不”。
CB Bailey 2012年

很好奇这个答案是如何被接受的,而实际上@CharlesBailey的评论才是正确的答案。
John Dibling 2012年

@约翰:我也很想。但是我认为一二拳对我有很好的效果,因为我给出了简短的总结,而查尔斯有趣地扩展了人们容易忘记正确处理的各种方式。不幸的是,您不会从投票数过多的评论中获得声誉。

查尔斯没有提供答案,而且这个A(与另一个A不同)在A和注释中都有解释。
NoSenseEtAl 2012年

9

C ++常见问题对此进行了很好的讨论:

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

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


2
像往常一样,常见问题解答的措词不当。您可以按值或参考来捕获。指针恰好是一个值(您可以通过值或引用来捕获它)。请记住,该类型A与该类型是不同的,A*所以如果我这样做,throw A()我将无法抓住catch(A* e)它,因为它是完全不同的类型。
马丁·约克

这些链接现在已断开。
stephenspann 2015年

1
我修复了@spanndemic链接
user1202136

1

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.