Don’t do this!
Monday, September 21st, 2009Don’t ever do this:
try {
...
} catch (std::exception e) {
throw e;
}
It doesn’t do what you think it does!
Unless you think it construct and then deconstructs an exception and throws away the type information about the original exception, in which case it does exactly what you think it does.
Of course, that might be the whole point of this piece of code, but why anyone would want to throw away information about which exception was thrown is beyond me.
Catching by value just means that you are creating a new object, but an exception is already copied when thrown, so there is no point. You save the copying by catching by reference.
Throwing the explicit copy means you slice away the dynamic type, so the (re-)thrown exception has a different type than the original exception, so you have no way of knowing which kind of exception was originally thrown.
Catching by reference doesn’t help you here, since “throw e” when “e” has a type means you throw with the static type of “e”, not the dynamic type, so you will still slice away the type.
Consider this small example:
#include <iostream>
struct Exception {};
struct SpecialException : public Exception {};
void foo() { throw SpecialException(); }
void bar() {
try { foo(); }
catch (Exception e) { throw e; }
}
void baz() {
try { foo(); }
catch (Exception &e) { throw; }
}
int main() {
try { foo(); }
catch (SpecialException &e) {
std::cout << "foo threw special" << std::endl;
} catch (Exception &e) {
std::cout << "foo threw plain" << std::endl;
}
try { bar(); }
catch (SpecialException &e) {
std::cout << "bar threw special" << std::endl;
} catch (Exception &e) {
std::cout << "bar threw plain" << std::endl;
}
try { baz(); }
catch (SpecialException &e) {
std::cout << "baz threw special" << std::endl;
} catch (Exception &e) {
std::cout << "baz threw plain" << std::endl;
}
return 0;
}
Here “bar” will throw away the type information, while “baz” will not.
The result is this:
$ ./foo foo threw special bar threw plain baz threw special
In the original example, I’m also a bit puzzled as to the reasoning behind it. Not catching the exception in the first place seems to me a better approach than catching it and just rethrowing it, without any further processing. The code really only contributes by adding a bit of overhead and removing useful type information.
PS. Yes, I stumbled over code exactly like this in a library I’m working with, which prompted this post…
–
264-297=-33


