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.
What is the correct way, are both OK, if so is there any difference?
我一直认为你不需要/不应该在这里使用new。正确的方法是什么,都可以吗?如果可以,有什么区别吗?
BTW from what I can see while "grepping" with PowerShell boost libs never use throw new
.
顺便说一句,从我所看到的,当“加油”与PowerShell增强libs从来没有使用扔新的。
P.S. also I found some CLI code that uses throw gcnew
. Is that OK?
另外,我还发现了一些使用throw gcnew的CLI代码。这样可以吗?
4 个解决方案
#1
76
The conventional way to throw and catch exceptions is to throw an exception object and to catch it by reference (usually const
reference). 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.
抛出和捕获异常的常规方法是抛出异常对象并通过引用(通常是const引用)捕获它。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. (The only exception being if it is never caught at all but this is a non-recoverable situation whichever way you look at it.)
向动态分配的对象抛出指针从来都不是一个好主意。异常可以使您在错误条件下编写更健壮的代码。如果您以传统的方式抛出异常对象,您可以确定它是否被命名为正确类型的catch子句捕获,是否被catch(…)捕获,是否被重新抛出,它是否将在适当的时候被正确地销毁。(唯一的例外是,如果它从未被捕捉到,但无论从哪个角度看,这都是不可恢复的情况。)
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. Your exception must never be caught by catch (...)
unless that block re-throws the exception which is then caught be another catch block that does deal correctly with the exception.
如果你向一个动态分配的对象抛出一个指针,你必须确保无论调用堆栈是什么样子,你都要抛出异常,这里有一个catch块,它指定正确的指针类型,并有适当的删除调用。您的异常决不能被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.
实际上,这意味着您已经采取了异常处理特性,这将使编写健壮的代码变得更加容易,并且使得编写在所有情况下都是正确的代码变得非常困难。这就忽略了这样一个问题,即几乎不可能作为不需要此特性的客户端代码的库代码。
#2
28
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.
注意,您应该直接或间接地从std::exception派生。
#3
21
Throwing new std::exception
is correct if the call site is expecting to catch a 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::异常是正确的,如果调用站点期望捕获std::异常*。但是没有人会期望捕捉到一个异常的指针。即使您的函数就是这样做的,并且人们阅读了文档,他们仍然很容易忘记并试图捕获对std::exception对象的引用。
#4
7
The C++ FAQ has a nice discussion on this:
c++ FAQ对此进行了很好的讨论:
- https://isocpp.org/wiki/faq/exceptions#what-to-catch
- https://isocpp.org/wiki/faq/exceptions what-to-catch
- 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."
基本上,“除非有一个很好的理由不这么做,否则通过引用来捕获。”避免按值捕获,因为这会导致复制,并且复制可以具有与抛出的内容不同的行为。只有在非常特殊的情况下,你才能用指针捕捉。
#1
76
The conventional way to throw and catch exceptions is to throw an exception object and to catch it by reference (usually const
reference). 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.
抛出和捕获异常的常规方法是抛出异常对象并通过引用(通常是const引用)捕获它。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. (The only exception being if it is never caught at all but this is a non-recoverable situation whichever way you look at it.)
向动态分配的对象抛出指针从来都不是一个好主意。异常可以使您在错误条件下编写更健壮的代码。如果您以传统的方式抛出异常对象,您可以确定它是否被命名为正确类型的catch子句捕获,是否被catch(…)捕获,是否被重新抛出,它是否将在适当的时候被正确地销毁。(唯一的例外是,如果它从未被捕捉到,但无论从哪个角度看,这都是不可恢复的情况。)
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. Your exception must never be caught by catch (...)
unless that block re-throws the exception which is then caught be another catch block that does deal correctly with the exception.
如果你向一个动态分配的对象抛出一个指针,你必须确保无论调用堆栈是什么样子,你都要抛出异常,这里有一个catch块,它指定正确的指针类型,并有适当的删除调用。您的异常决不能被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.
实际上,这意味着您已经采取了异常处理特性,这将使编写健壮的代码变得更加容易,并且使得编写在所有情况下都是正确的代码变得非常困难。这就忽略了这样一个问题,即几乎不可能作为不需要此特性的客户端代码的库代码。
#2
28
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.
注意,您应该直接或间接地从std::exception派生。
#3
21
Throwing new std::exception
is correct if the call site is expecting to catch a 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::异常是正确的,如果调用站点期望捕获std::异常*。但是没有人会期望捕捉到一个异常的指针。即使您的函数就是这样做的,并且人们阅读了文档,他们仍然很容易忘记并试图捕获对std::exception对象的引用。
#4
7
The C++ FAQ has a nice discussion on this:
c++ FAQ对此进行了很好的讨论:
- https://isocpp.org/wiki/faq/exceptions#what-to-catch
- https://isocpp.org/wiki/faq/exceptions what-to-catch
- 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."
基本上,“除非有一个很好的理由不这么做,否则通过引用来捕获。”避免按值捕获,因为这会导致复制,并且复制可以具有与抛出的内容不同的行为。只有在非常特殊的情况下,你才能用指针捕捉。