Issue the Second: (Mis)understandings
The second issue has to do with knowing what you're getting. As many notable persons, including the authors of the Boost exception specification rationale [BoostES], have put it, programmers tend to use exception specifications as though they be-haved the way the programmer would like, instead of the way they actually do be-have.
Hence the question:
4.What are exception specifications, and what do they do? Be precise.
Here's what many people think exception specifications do:
*Guarantee that functions will throw only listed exceptions (possibly none).
*Enable compiler optimizations based on the knowledge that only listed exceptions (possibly none) will be thrown.
These expectations are, again, deceptively close to being correct. Consider again the code in Example 13-2(b):
Code:
// Example 13-2(b) reprise, and two potential white lies:
//
int Gunc() throw(); // will throw nothing ?
int Hunc() throw(A,B); // can only throw A or B ?
Are the comments correct? Not quite. Gunc might indeed throw something, and Hunc might well throw something other than A or B! The compiler just guarantees to beat them senseless if they do… oh, and to beat your program senseless too, most of the time.
Because Gunc or Hunc could indeed throw something they promised not to, not only can't the compiler assume it won't happen, but the compiler is also responsible for being the policeman with the billy club who checks to make sure such a bad thing doesn't happen undetected. If it does happen, then the compiler must invoke the unexpected function. Most of the time, that will terminate your program. Why? Because there are only two ways out of unexpected, neither of which is a normal return. You can pick your poison:
*Throw instead an exception that the exception specification does allow. If so, the exception propagation continues as it would normally have. But remember that the unexpected handler is global—there is only one for the whole program. A global handler is highly unlikely to be smart enough to Do the Right Thing for any given particular case, and the result is to go to terminate, go directly to terminate, do not pass catch, do not collect $200.
*Throw instead (or rethrow) an exception that the exception specification (still) doesn't allow. If the original function allowed a bad_exception type in its exception specification, okay, then it's a bad_exception that will now get propagated. But if not, then go to terminate, go directly to terminate…
Because violated exception specifications end up terminating your program the vast majority of the time, I think it's legitimate to call that "beating your program senseless."
Earlier, we saw two bullets stating what many people think that exception specifications do. Here is an edited statement that more accurately portrays what they actually do do [sic]:[19]
[19] Yes, this is a sic joke.
*Guarantee Enforce at run-time that functions will throw only listed exceptions (possibly none).
*Enable or prevent compiler optimizations based on the knowledge that only listed exceptions (possibly none) will be thrown having to check whether listed exceptions are indeed being thrown.
To see what a compiler has to do, consider the following code, which provides a body for one of our sample functions, Hunc:
Code:
// Example 13-4(a)
//
int Hunc() throw(A,B) {
return Junc();
}
Functionally, the compiler must generate code like the following, and it's typically just as costly at run-time as if you'd hand-written it yourself (though less typing because the compiler generates it for you):
Code View: Scroll / Show All
Code:
// Example 13-4(b): A compiler's massaged version of Example 13-4(a)
//
int Hunc()
try {
return Junc();
}
catch(A) {
throw;
}
catch(B) {
throw;
}
catch(…) {
std::unexpected(); // won't return! but might throw an A or a B if you're lucky
}
Here we can see more clearly why, rather than letting the compiler make optimizations by assuming only certain exceptions will be thrown, it's exactly the reverse: The compiler has to do more work to enforce at run-time that only those exceptions are indeed thrown.