我在遗留代码库中有以下结构:
try{
...
}
catch(Type1&){
...
}
catch(Type2&){
...
}
...
通过复制粘贴开发,相同的catch块随处可见。 现在,我会编写一个这样的函数:
void catchErrors(){
try{
throw;
}
catch(Type1&){
...
}
...
}
并将其放入代码中:
try{
...
}
catch(...){
catchErrors();
}
这是一个有效的重构器,导致相同的功能吗?
(你对重构有什么更好的建议吗?)
答案 0 :(得分:5)
是的,这是有效的。
[C++14: 15.1/8]
:没有操作数的 throw-expression 重新抛出当前处理的异常(15.3)。使用现有异常对象重新激活该异常;没有创建新的异常对象。唯一的例外是否定的 更长时间被认为被捕;因此,std::uncaught_exception()
的值将再次成立。[例如:由于异常而必须执行但仍无法完全处理异常的代码可以这样编写:
try { // ... } catch (...) { // catch all exceptions // respond (partially) to exception throw; // pass the exception to some // other handler }
-end example]
[C++14: 15.1/9]:
如果当前没有处理异常,则执行不带操作数的throw-expression调用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!
答案 1 :(得分:3)
是的,您的重构是有效的。实际上,它是一种相当古老的技术,专门用于将异常处理程序集移动到另一个函数中,并允许它们重用。
请注意,如果在异常处理块之外调用CatchErrors()
,则调用std::terminate()
将调用throw;
。如果没有处理异常,则需要main()
语句。
只是不要太依赖这项技术。最好通过一些异常安全保证来设计大多数函数(即,如果抛出异常并且它们不调用它们它们将不会出现故障)。这样可以更有可能集中处理异常处理(例如在gcc -o prog prog.c -lm -fopenmp
中),而不是拥有许多必须分别处理异常的不同功能。这样做可以减少重用异常处理代码的需要,因为大多数异常只能在一个地方处理。