+3  A: 

Clever code - kudos to potatoswatter on this one. I think that I would have to find some way around the last item though.

  1. throw; rethrows the active exception. It is only valid if a catch block is on the stack. I can't recall where I came across that tidbit at but it was probably on SO in the context of some other question. The bare throw gives us access to the current exception by catching it in the chained_exception constructor. In other words, prev in the constructor is a reference to the exception that we are currently processing.

  2. You are correct here. This prevents double deletion.

  3. The sentinel exception, the one thrown in main, should never be deleted. The one identifying attribute of this exception is that it's link member is NULL.

  4. This is the part that I don't like but cannot think of an easy way around. The only visible chained_exception constructor can only be called when a catch block is active. IIRC, a bare throw without an active catch block is a no-no. So, the workaround is to throw in main and put all of your code in the catch block.

Now, if you try this method in multi-threaded code, make sure that you understand (4) very well. You will have to replicate this in your thread entry point.

D.Shawley
+1, yep, thank you. One other place you might have seen this trick is http://stackoverflow.com/questions/2487509/are-c-exceptions-sufficient-to-implement-thread-local-storage, which specifically deals with multithreading as you describe.
Potatoswatter
Thank you very much for your answer, D.Shawley. Section 1 was very sneaky way to do the chaining; I didn't know you could use `throw;` *outside* a `catch` block as long as you at least have a `catch` block on the stack. Is this what causes the need for a dummy exception? What would happen if you invoked `throw;` outside a `catch` block? Section 3 makes sense now; of course you would not want to try deleting the active exception. That would wreck havoc indeed.
gablin
@gablin: yep, `throw;` with no `catch` "on the stack" results in immediate termination of the program.
Potatoswatter
gablin
@gablin: the fundamental problem, and the motivation for doing it this way, is that every operation that may throw won't always have a pointer to the current exception. Ensuring that they do will either take a lot of cumbersome argument passing (the antithesis to native exceptions), or a global variable that entirely precludes multithreading.
Potatoswatter
@Potatoswatter: Ah. But is that common? I mean, is such a feature really that necessary that we must put up with having the "null" exception?
gablin