2

我在旧代码库中有以下结构:

try{
...
}
catch(Type1&){
...
}
catch(Type2&){
...
}
...

随着复制粘贴的发展,相同的捕获块出现在任何地方。现在,我会写一个这样的函数:

void catchErrors(){
  try{
    throw;
  }
  catch(Type1&){
    ...
  }
  ...
}

并将其放入如下代码中:

try{
  ...
}
catch(...){
  catchErrors();
}

这会是一个有效的重构,从而产生相同的功能吗?
(你对重构有什么更好的建议吗?)

4

2 回答 2

5

是的,这是有效的。

[C++14: 15.1/8]:没有操作数的throw 表达式重新抛出当前处理的异常 (15.3)。使用现有的异常对象重新激活异常;没有创建新的异常对象。不再认为异常被捕获;因此, 的值std::uncaught_exception()将再次为真。

[ 示例:由于异常而必须执行但不能完全处理异常的代码可以这样写:

try {
  // ...
} catch (...) { // catch all exceptions
  // respond (partially) to exception
  throw; // pass the exception to some
  // other handler
}

—结束示例]

[C++14: 15.1/9]:如果当前没有处理异常,则执行不带操作数调用的 throw 表达式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!

现场演示

于 2015-10-05T10:09:20.093 回答
3

是的,您的重构是有效的。事实上,它是一种相当古老的技术,专门设计用于将异常处理程序集移动到另一个函数中,并允许它们重用。

请注意,如果在异常处理块之外调用您CatchErrors()将调用它。如果没有处理异常,则声明std::terminate()中需要这样做。throw;

只是不要过于依赖技术。最好为大多数函数设计一些异常安全保证(即,如果抛出异常并且它们不调用它,它们不会发生故障)。这允许更多的机会集中您的异常处理(例如 in main()),而不是拥有许多必须分别处理异常的不同功能。这样做可以减少重用异常处理代码的需要,因为大多数异常只会在一个地方处理。

于 2015-10-05T10:27:44.107 回答