I have the following structure in the legacy codebase:
try{
...
}
catch(Type1&){
...
}
catch(Type2&){
...
}
...
And with copy-paste development, the same catch blocks show up everywhere. Now, I would write a function like this:
void catchErrors(){
try{
throw;
}
catch(Type1&){
...
}
...
}
and put it into the code like this:
try{
...
}
catch(...){
catchErrors();
}
Will this be a valid refactor, resulting in the same functionality?
(And do you have any better suggestion for the refactor?)
Yes, that's valid.
[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).
Although the throw-expression has been moved into its own function, during its execution an exception is still being handled, so it still works:
#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!