I just finished work on a C++-program where I've implemented my own exceptions (although derived from std::exception). The practice I've applied when one exception causes a chain reaction, propagating the error upwards and giving rise to other exceptions, is to concatenate the error message at each appropriate step across the modules (read classes). I.e. the old exception itself is dropped and a new exception is created, but with a longer error message.
This may have worked for my small program, but I wasn't very satisfied with my approach in the end. For one, line numbers (although not applied at the moment) and file names are not retained except for the last exception; and really that information is of most interest in the first exception.
I figure this could have been handled better by chaining exceptions together; i.e. the old exception is provided in the constructor of the new exception. But how would that be implemented? Does not exceptions die when they go out of scope from the method, thereby preventing one to use exception pointers? And how to copy and store the exception if the exception can be of any derived class?
This ultimately lead me to consider whether chaining exceptions in C++ is such a good idea after all. Perhaps one should just create one exception and then add additional data to that (like I've been doing, but probably in a much better manner)?
What is your response to this? Should exceptions caused by another be chained together to retain a sort of "exception trace" -- and how should that be implemented? -- or should a single exception be used and additional data attached to it -- and how should that be done?
It is necessary to copy the data out of an exception object, into a chain, if you want it to outlive the
catch
block that receives it, aside from rethrow bythrow;
. (Which includes, for example, if thatcatch
block exits through athrow obj;
.)This can be done by putting data to be saved on the heap, and implementing
swap
(move
in C++0x) on your private data inside the exception, for example.Of course, you need to be careful when using the heap with exceptions… but then again, in most modern OSes, memory overcommitment completely prevents
new
from ever throwing, for better or for worse. A good memory margin and dropping exceptions from the chain upon complete meltdown should keep it safe.output (appropriately grumpy):