简体   繁体   English

抛出新的 std::exception 与抛出 std::exception

[英]throw new std::exception vs throw std::exception

while looking at some code I stumbled onto:在查看我偶然发现的一些代码时:

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

and I always thought that you don't need/you shouldn't use new here.我一直认为你不需要/你不应该在这里使用new
What is the correct way, are both OK, if so is there any difference?什么是正确的方法,都可以,如果可以,有什么区别吗?

BTW from what I can see while "grepping" with PowerShell boost libs never use throw new .顺便说一句,从我在使用 PowerShell boost 库“grepping”时所看到的,从不使用throw new

PS also I found some CLI code that uses throw gcnew . PS 我还发现了一些使用throw gcnew CLI 代码。 Is that OK?那样可以么?

The conventional way to throw and catch exceptions is to throw an exception object and to catch it by reference (usually const reference).抛出和捕获异常的常规方法是抛出一个异常对象并通过引用(通常是const引用)捕获它。 The C++ language requires the compiler to generate the appropriate code to construct the exception object and to properly clean it up at the appropriate time. C++ 语言要求编译器生成适当的代码来构造异常对象并在适当的时候适当地清理它。

Throwing a pointer to a dynamically allocated object is never a good idea.抛出一个指向动态分配对象的指针从来都不是一个好主意。 Exceptions are supposed to enable you to write more robust code in the face of error conditions.异常应该使您能够在面对错误情况时编写更健壮的代码。 If you throw an exception object in the conventional manner you can be sure that whether it is caught by a catch clause naming the correct type, by a catch (...) , whether it is then re-thrown or not it will be destroyed correctly at the appropriate time.如果您以常规方式抛出异常对象,您可以确定它是否被命名正确类型的 catch 子句捕获,通过catch (...) ,无论它是否被重新抛出,它都会被销毁在适当的时候正确。 (The only exception being if it is never caught at all but this is a non-recoverable situation whichever way you look at it.) (唯一的例外是如果它根本没有被捕获,但无论您怎么看,这都是不可恢复的情况。)

If you throw a pointer to a dynamically allocated object you have to be sure that whatever the call stack looks like at the point you want to throw your exception there is a catch block that names the correct pointer type and has the appropriate delete call.如果你抛出一个指向动态分配对象的指针,你必须确保无论调用堆栈在你想要抛出异常的点上是什么样子,都有一个 catch 块,它命名了正确的指针类型并具有适当的delete调用。 Your exception must never be caught by catch (...) unless that block re-throws the exception which is then caught by another catch block that does deal correctly with the exception.您的异常绝不能被catch (...)捕获,除非该块重新抛出异常,然后该异常被另一个正确处理异常的 catch 块捕获。

Effectively, this means you've taken the exception handling feature that should make it easier to write robust code and made it very hard to write code that is correct in all situations.实际上,这意味着您已经采用了异常处理功能,该功能应该可以更轻松地编写健壮的代码,并使编写在所有情况下都正确的代码变得非常困难。 This is leaving aside the issue that it will be almost impossible to act as library code for client code that won't be expecting this feature.这撇开了一个问题,即几乎不可能充当不期望此功能的客户端代码的库代码。

No need to use new when throwing exception.抛出异常时无需使用new

Just write:写就好了:

throw yourexception(yourmessage);

and catch as :并捕获为:

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

Note that yourexception should derive from std::exception directly or indirectly.请注意, yourexception应直接或间接从std::exception派生。

Throwing new std::exception is correct if the call site is expecting to catch a std::exception* .如果调用站点期望捕获std::exception*则抛出new std::exception是正确的。 But nobody will be expecting to catch a pointer to an exception.但是没有人会期望捕获指向异常的指针。 Even if you document that's what your function does and people read the documentation, they're still liable to forget and try to catch a reference to a std::exception object instead.即使你记录了你的函数所做的事情并且人们阅读了文档,他们仍然容易忘记并尝试捕获对std::exception对象的引用。

The C++ FAQ has a nice discussion on this: C++ FAQ 对此有一个很好的讨论:

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

Basically "unless there's a good reason not to, catch by reference. Avoid catching by value, since that causes a copy to be made and the copy can have different behavior from what was thrown. Only under very special circumstances should you catch by pointer."基本上“除非有充分的理由不这样做,否则按引用捕获。避免按值捕获,因为这会导致创建副本,并且副本的行为可能与抛出的行为不同。只有在非常特殊的情况下,您才应该通过指针捕获。 ”

Operator new cannot guarantee that it will never raise an exception.运算符 new 不能保证它永远不会引发异常。 For this reason using it for throwing a "valid" (intended) exception would produce a code that cannot be guaranteed not to crash.出于这个原因,使用它来抛出一个“有效”(预期的)异常会产生一个不能保证不会崩溃的代码。 Since there may be only one exception at a time, and your program tries to throw two before any of them can be caught, the best thing an implementation can do is to immediately abort your program, eg by calling std::terminate.由于一次可能只有一个异常,并且您的程序试图在它们中的任何一个被捕获之前抛出两个异常,因此实现可以做的最好的事情是立即中止您的程序,例如通过调用 std::terminate。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM