我仍然可以从 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() 中),而不是拥有许多必须分别处理异常的不同函数。这样做减少了重用异常处理代码的需要,因为大多数异常将只在一个地方处理。