我仍然可以从 catch 块中调用的函数中重新抛出异常吗?
Can I still rethrow an exception from within a function called within a catch block?
我在遗留代码库中有以下结构:
try{
...
}
catch(Type1&){
...
}
catch(Type2&){
...
}
...
通过复制粘贴开发,相同的 catch 块随处可见。
现在,我会写一个这样的函数:
void catchErrors(){
try{
throw;
}
catch(Type1&){
...
}
...
}
并像这样将其放入代码中:
try{
...
}
catch(...){
catchErrors();
}
这会是一个有效的重构,从而产生相同的功能吗?
(您对重构有什么更好的建议吗?)
是的,有效。
[C++14: 15.1/8]
: A throw-expression with no operand rethrows the currently handled exception (15.3). The exception is reactivated with the existing exception object; no new exception object is created. The exception is no
longer considered to be caught; therefore, the value of std::uncaught_exception()
will again be true.
[ Example: code that must be executed because of an exception yet cannot completely handle the exception can be written like this:
try {
// ...
} catch (...) { // catch all exceptions
// respond (partially) to exception
throw; // pass the exception to some
// other handler
}
—end example ]
[C++14: 15.1/9]:
If no exception is presently being handled, executing a throw-expression with no operand calls std::terminate()
(15.5.1).
虽然 throw-expression 已经被移动到它自己的函数中,但是在它执行的过程中仍然在处理一个异常,所以它仍然有效:
#include <iostream>
void bar()
{
try {
throw;
}
catch (int x) {
std::cerr << "Damn " << x << "!\n";
}
}
void foo()
{
try {
throw 42;
}
catch (...) {
bar();
}
}
int main()
{
foo();
}
// Output: Damn 42!
(live demo)
是的,您的重构有效。事实上,这是一项相当古老的技术,专门设计用于将异常处理程序集移动到另一个函数中,并允许它们重用。
请注意,如果在异常处理块之外调用 CatchErrors()
,则调用 std::terminate()
。如果没有处理异常,throw;
语句需要这样做。
只是不要过分依赖技术。最好用一些异常安全保证来设计你的大部分函数(即,如果抛出异常并且它们不调用它,它们就不会发生故障)。这允许更多机会集中处理异常(例如在 main()
中),而不是拥有许多必须分别处理异常的不同函数。这样做减少了重用异常处理代码的需要,因为大多数异常将只在一个地方处理。
我在遗留代码库中有以下结构:
try{
...
}
catch(Type1&){
...
}
catch(Type2&){
...
}
...
通过复制粘贴开发,相同的 catch 块随处可见。 现在,我会写一个这样的函数:
void catchErrors(){
try{
throw;
}
catch(Type1&){
...
}
...
}
并像这样将其放入代码中:
try{
...
}
catch(...){
catchErrors();
}
这会是一个有效的重构,从而产生相同的功能吗?
(您对重构有什么更好的建议吗?)
是的,有效。
[C++14: 15.1/8]
: A throw-expression with no operand rethrows the currently handled exception (15.3). The exception is reactivated with the existing exception object; no new exception object is created. The exception is no longer considered to be caught; therefore, the value ofstd::uncaught_exception()
will again be true.[ Example: code that must be executed because of an exception yet cannot completely handle the exception can be written like this:
try { // ... } catch (...) { // catch all exceptions // respond (partially) to exception throw; // pass the exception to some // other handler }
—end example ]
[C++14: 15.1/9]:
If no exception is presently being handled, executing a throw-expression with no operand callsstd::terminate()
(15.5.1).
虽然 throw-expression 已经被移动到它自己的函数中,但是在它执行的过程中仍然在处理一个异常,所以它仍然有效:
#include <iostream>
void bar()
{
try {
throw;
}
catch (int x) {
std::cerr << "Damn " << x << "!\n";
}
}
void foo()
{
try {
throw 42;
}
catch (...) {
bar();
}
}
int main()
{
foo();
}
// Output: Damn 42!
(live demo)
是的,您的重构有效。事实上,这是一项相当古老的技术,专门设计用于将异常处理程序集移动到另一个函数中,并允许它们重用。
请注意,如果在异常处理块之外调用 CatchErrors()
,则调用 std::terminate()
。如果没有处理异常,throw;
语句需要这样做。
只是不要过分依赖技术。最好用一些异常安全保证来设计你的大部分函数(即,如果抛出异常并且它们不调用它,它们就不会发生故障)。这允许更多机会集中处理异常(例如在 main()
中),而不是拥有许多必须分别处理异常的不同函数。这样做减少了重用异常处理代码的需要,因为大多数异常将只在一个地方处理。