From: dave@boostpro.com   
      
   on Sun Jun 24 2012, DeMarcus wrote:   
      
   >> There's no new "resource leak problem." Anytime you have an   
   >> un-managed resource you have to watch out for exceptions. Any   
   >> resources managed directly by an object become un-managed when you   
   >> enter the destructor body. Either don't throw an exception from   
   >> destructors of such objects (status quo), or (better) delegate   
   >> resource management to a sub-object.   
   >   
   > Ok, I start to understand. Put all resources in their own managed RAII   
   > objects.   
   >   
   >>> 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.   
   >>   
   >> What do you mean by "undetermined behavior?" The behavior of dtors   
   >> in the presence of exceptions is well-specified, and actually pretty   
   >> reasonable: when not already unwinding, the rest of the current   
   >> dtor's body is skipped but all of the other sub-objects are   
   >> destroyed as part of unwinding. If you don't like that behavior,   
   >> well, don't throw from your destructor. But if you want to throw   
   >> from your destructor you can easily work with these semantics to get   
   >> a useful "determined" result.   
   >   
   > My undetermined behavior idea will be obsolete with managed resources,   
   > so I skip explaining that further.   
   >   
   >>> 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.   
   >>   
   >> Actually, we plan to propose a handler (like the standard unexpected   
   >> handler) that can do anything it wants with the secondary exception,   
   >> including logging or chaining it. And if you do chain it, the root   
   >> cause of unwinding should stay at the head of the chain.   
   >   
   > Ok good, but how do you come to the conclusion that you want the root   
   > cause at the /head/?   
      
   It's like this: the initial operation requested by the "user" failed   
   because of the root cause. If the destructor hadn't thrown anything,   
   that's what we'd hear about. Secondary failures during cleanup are   
   *typically* resource-release failures, which are *typically* fairly   
   benign and of less interest to the caller; they don't describe why the   
   requested operation failed. Ignoring them might even be a reasonable   
   approach. So it doesn't seem reasonable to replace the head of the   
   chain.   
      
   > Let's say you get an out-of-bounds exception, someone catches it and   
   > chains it with an XML-error exception, throws that to someone that   
   > catches it and chains it with a PreferenceFile-read-error exception and   
   > throws that. What is the catcher of that chained exception going to do   
   > with an out-of-bounds exception?   
      
   Exactly what he'd have done had there been no failure during cleanup:   
   deal with the original cause of the failure.   
      
   > I claim that the most recent exception must be what is caught at the   
   > next catch().   
      
   I disagree. Suppose you have a recovery action for the most recent   
   exception, and you take it, and retry? The original reason for failure   
   persists, and the operation still fails. Not good.   
      
   >>> 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.   
   >>   
   >> Reading logs is not for the faint-of-heart already. I don't see how   
   >> this is going to make anything worse.   
   >   
   > You have convinced me that managed resources solve resource leaks but   
   > I'm still not convinced about the independent exceptions. Strong-heart   
   > people may be able to read cryptic logs (not that I would prefer that)   
   > but how are they going to be able to choose which of the independent   
   > exceptions shall take the head in the chain?   
      
   Huh? Log readers don't make that choice. It's up to the person   
   writing the log whether they want to even represent that information,   
   and if they represent it, how they do it.   
      
   >>> 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.   
   >>   
   >> No, those are imaginary problems, unless you choose to both   
   >>   
   >> a) throw from your destructor, and   
   >> b) ignore the specified semantics of throwing from destructors   
   >   
   > We agree on a), but in b) the specified semantics would involve   
   > prioritizing one independent exception from another.   
      
   Agreeing on one part of that statement is meaningless: a and b go   
   together inextricably. My point is that (a) you have a choice about   
   whether to throw from a dtor, and (b) the semantics of throwing from   
   dtors is well-specified and not even particularly hard to code with. So   
   if you (a) choose to throw from dtors, don't (b) ignore the specified   
   semantics and you'll see no resource leaks or undefined behavior (and I   
   stipulate that avoiding unwinding/termination requires a language   
   change). To agree with (a) by itself would be like saying, "if you   
   choose throw from a destructor" but then stopping there without saying   
   anything else.   
      
   AFAICT, you are making a different claim, about whether it makes sense   
   to gather exceptions into a chain and how they should be dealt with when   
   they are chained. That is a completely separate issue from undefined   
   behavior and resource leaks. However, what claim you are actually   
   making is pretty vague.   
      
   > That prioritization is not obvious and I claim it must not be left as   
   > a side task.   
      
   What do you mean by a "side task?"   
      
   My plan is to leave it up to the author of the hook function for dealing   
   with nested exceptions. My claim is that "ignore secondary exceptions"   
   might be a reasonable default, "chain the secondary exception to the   
   first" might be better, "terminate" would be what you'd choose for   
   absolute backward compatibility, and if you are are foolish enough to   
   disagree with me about what should be at the head of the chain then   
   you're free to do it the "wrong" way ;-)   
      
   Regards,   
      
   --   
   Dave Abrahams   
   BoostPro Computing   
      
   [continued in next message]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|