From: use_my_alias_here@hotmail.com   
      
   On 2012-06-17 22:24, Dave Abrahams wrote:   
   > on Fri Jun 15 2012, DeMarcus wrote:   
   >   
   >> I have always had the feeling that throwing from   
   >> a destructor is a bad idea, but I've never seen a proof that it will   
   >> be impossible even with future C++. Therefore I tried to state such   
   >> "proof".   
   >>   
   >> With the input from the people here I managed to come up with an even   
   >> better "proof" (at least in regards to convince myself). It's the   
   >> following.   
   >   
   > I don't understand the drive to convince yourself that the idea of   
   > throwing from destructors is somehow fundamentally broken.   
   >   
      
   It's just my interest within programming. Right now I'm into exploring   
   failure handling, and I try to see what exception handling could look   
   like in ten years from now.   
      
   >> We can't throw from destructors unless we are able to bulk up all   
   >> exceptions thrown from all the destructors until the first catch.   
   >   
   > Either that, or throw out information from secondary exceptions.   
   >   
   >> Even if that was possible we would need to choose between   
   >>   
   >> 1. Just running each destructor until it throws and then proceed with   
   >> the next destructor.   
   >>   
   >> 2. Running the whole destructor even if it throws (bulking it).   
   >   
   > I don't unknw what either of these things mean. C++ already has   
   > well-defined semantics for what happens when a dtor throws, but not during   
   > stack unwinding. It's easy to extend these semantics for exceptions   
   > thrown during unwinding if you're willing to chain up multiple   
   > exceptions or throw out secondary exception information.   
   >   
      
   I apologize. I realize that I'm not clear with what I write so I'll try   
   to explain better.   
      
   If we allow throwing from destructors and want to be able to handle that   
   scenario, we must be prepared to take care of all exceptions that can be   
   thrown during unwinding. Right now we terminate if we throw an exception   
   while another one is active.   
      
   Let's look at scenario 1) above.   
      
   One way to allow throwing from destructors (that works with current C++)   
   is to chain exceptions to avoid termination, i.e. if you need to throw   
   yet another exception during stack unwinding, you catch the active   
   exception and chain it with the new exception and throw that.   
      
   Even though we have circumvented the termination problem with this   
   solution we still face the resource leak problem since the destructors   
   most often must release the resources the very last thing they do.   
      
   Now let's look at scenario 2) above (never mind the bulking, I'll come   
   to that).   
      
   You may be able (even with current C++) to queue up exceptions in a   
   destructor, chain them all in the end of the destructor and throw. Now   
   you have solved the resource release problem but most certainly the   
   destructor will have undetermined behavior since code after an exception   
   should not be executed.   
      
      
   Above is convincing enough for me to not throw from destructors.   
   Nevertheless, if one would try anyway we hit another problem.   
      
   The exception chaining will chain every exception it encounters. The   
   idea (as I see it) with chaining is that you should be able to follow   
   the exception and what caused it, look at its parent exception in the   
   chain and its parent to finally see the root cause. This could be good   
   in a logging system.   
      
   Now if you are unfortunate, a destructor during unwinding may throw an   
   exception that is independent of the active exception, but will still be   
   part of the chain, causing confusion if the whole chain is written to a log.   
      
   That is what I meant with bulking exceptions. Bulking is a pure   
   hypothetical non-C++ way of bulking up several exception chains to be   
   thrown if several unrelated problems arises during unwinding. As I write   
   I think it may even be feasible to have a main exception that contains a   
   list of exception chains, but we will still suffer from resource leaks   
   or undefined behavior.   
      
      
   >> In 1. we would likely have resource leaks. In 2. we would likely have   
   >> undetermined behavior.   
   >   
   > These conclusions seem flimsy at best and completely unsupported at   
   > worst. If you code to account for the semantics of exceptions thrown   
   > from destructors, you can throw them. If you don't code to account for   
   > those semantics, throwing from a destructor is likely to do something   
   > undesirable. This is exactly the same as the way the use of any other   
   > feature (e.g. placement new) works if you account for its semantics, and   
   > will get you in trouble if you code as though it hadn't happened.   
   >   
      
   You write "If you code to account for the semantics of exceptions thrown   
   from destructors, you can throw them". That is what I try to say is   
   close to impossible. Let's make a simple example.   
      
   SomeClass::~SomeClass()   
   {   
    int* i = new int;   
    doSomethingWithInt( &i );   
      
    if( i == NULL )   
    throw "Error";   
    *i = 4711;   
      
    delete i;   
   }   
      
   If you choose 1) from above, you will have a resource leak.   
   If you choose 2) from above, (assuming a future C++ would queue the   
   exception for you) you would crash the row after queuing the exception.   
      
      
   Regards,   
   Daniel   
      
      
   --   
    [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
    [ comp.lang.c++.moderated. First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|