Re: What risk of undefined behavior if destructor must throw?
Terry G wrote:
In my example, ReleaseMutex has failed. It shouldn't have,
but it did. Microsoft doesn't say why ReleaseMutex might
fail, until it actually does. Then you can call GetLastError
to find out why, after the fact. The point here is not that
Microsoft is evil, its just that destructors have to "trust"
that other code will succeed. But it might not.
So, in my destructor I have three choices: terminate right
now, ignore the error, or throw. Terminate seems drastic in
this example.
I'm not so sure. If you actually do hold the mutex, and for
some reason, the system cannot release it, your application is
hosed. About all you can do is get out as quickly as possible,
so that the backup can take over. (I can't actually think of
any case where this is possible, and Solaris doesn't provide an
error condition for it. But who knows.) If you don't hold the
mutex, but thought you did, then there is probably a serious
violation of your preconditions in the preceding code, which
also calls for getting out as quickly as possible. (On the
other hand, I can very well imagine scenarios in which you only
acquire the mutex under certain conditions, and you "expect"
this particular error in the other conditions. In which case,
it's not an error.)
Ignoring the error could cause the program to hang, become
unstable, or produce incorrect results, a fate worse than
death in an embedded system.
Unless you've designed it so that you may or may not hold the
mutex at this point, and the failure is because you aren't the
owner. I'm sceptical of such designs, but not to the point
where I'd say that they are never appropriate.
Throwing seems like the best choice here.
I can't see it. It's either a fatal error, or it's not an error
at all. I can't see any case where it might be a recoverable
error.
It seems to me to be the best choice most of the time. In
fact, I'd really like to throw something that forces the
program to terminate, because continuing to operate would be
bad.
If continuing to operate would be bad, you want to abort the
application as soon as possible, without stack walkback. If
your application data is corrupted, then executing additional
code is dangerous, including any code that might be in
destructors for on stack objects.
So shutdown gracefully. But shutdown!
However, most of my collegues have read these books and
routinely put catch(...) in their code.
What books? If a book recommends a catch(...) without a throw
in the catch block, I'd throw it out.
"Don't use catch(...)" seems like stronger advice than "don't
let destructors throw."
There are cases where catch(...) is appropriate. The rule
should be more along the lines that every catch(...) must have a
code block which ends with a parameter-less throw (or calls some
function which does a parameter-less throw).
That way I could throw a Terminate() exception, not derived
from anything, which would fully unwind the stack, and then
terminate.
That's for clean shutdown, when there is no error condition (and
I throw an int, which ends up as the return code---but of
course, int isn't derived from anything either).
--
James Kanze GABI Software
Conseils en informatique orient?e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S?mard, 78210 St.-Cyr-l'?cole, France, +33 (0)1 30 23 00 34
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]