home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c++.moderated      Moderated discussion of C++ superhackery      33,346 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 32,365 of 33,346   
   Zeljko Vrba to Thomas Richter   
   Re: Will we ever be able to throw from a   
   05 Jun 12 10:26:07   
   
   From: mordor.nospam@fly.srk.fer.hr   
      
   { Reformatted; please limit your lines to 70 characters, and   
      don't quote empty lines at the beginning or end of a paragraph   
      -mod/we }   
      
   On 2012-06-05, Thomas Richter  wrote:   
      
   > Can you? What happened with the object under destruction?   
   > Apparently, it is not properly destructed, otherwise there wouldn't   
   > be an exception, yet you have no longer a way of accessing this   
   > object and trying a different clean-up strategy.   
      
   You can wrap the relevant (not-yet-destructed) part of the object into   
   the exception object and try to deal with it in catch.  For example,   
   if the object wraps a file, you would transport its file-descriptor   
   through the exception to the catch site.   
      
   > True, but that's often the last resort - can one savely continue the   
   > program after terminate has been called? How?   
      
   No, but I think that double-exception is a grave enough scenario that   
   continuing is not an option.  x86 CPU shuts down on a triple fault for   
   example, so continuing isn't always an option for a CPU either.   
      
   [Side-note: the CPU shutdown condition is also signaled to external   
   pins and "caught" by the chipset which in turn (on desktop machines at   
   least) asserts the RESET pin and resets the CPU.  terminate() could   
   try to save the relevant state and reexec the program itself in order   
   to "continue".  This is platform-dependent, but doable.  Maybe   
   something to learn from HW design.]   
      
   > That handling cleanup errors (and others) requires cleanup of   
   > objects.   
      
   I'm not sure I get it.  If in `delete x;` the destructor throws, is   
   the memory freed?  This is basically the only piece of work that the   
   program can't do itself.   
      
   > This actually means, however, that you should better replace   
   > throwing in the destructor by an assert, or instead build an   
   > alternative   
      
   assert() should be understood as no-op, so it's not adequate   
   replacement.   
      
   > cleanup strategy into the destructor that can happen the error   
   > locally.   
      
   In general this means that the 1) object needs to know where it was   
   called from, or 2) I need many subclasses which differ only in their   
   destructors.   
      
   > The problem is that you cannot delegate the handling of cleanup   
   > errors as with other errors since the object that caused the problem   
   > is already no longer reachable.   
      
   You can copy the relevant part of the object and pass it as the part   
   of the exception.   
      
   > Are they? There are many error reporting algorithms, amongst them is   
   > also assert().   
      
   Why do you believe that crashing on assert() [assuming it's not a   
   noop] is better than std::terminate being called?  Neither allows you   
   to continue running "cleanly". (There are hacks to continue execution   
   -- longjmp -- but.. I don't want to go there.)   
      
   > If you throw an exception, the point is that there is somewhere a   
   > catch() that can deal with the situation - otherwise, you wouldn't   
   > throw in first place. That's quite logical. However, if by language   
      
   That may be the point, but it's not the *whole* point.  For example,   
   some STL algorithms throw (e.g., std::string methods throw on invalid   
   indices), but I never write corresponding catch.  End result: if my   
   program passes invalid index (i.e., it is buggy), it crashes, just as   
   it would after assert.   
      
   STL is thus an example of using exceptions as "always on" substitute   
   for assert().   
      
   > construct, you *cannot* deal with the situation since the object to   
   > deal with is no longer reachable, the catch is superfluous in first   
      
   The exception object can transport the relevant state of the deceased   
   object.  I'm repeating myself from the last post, but it seems that   
   this point hasn't come across since you're repeating this.   
      
   >> The real question is: should destructors be used to enofrce   
   >> invariants?  If yes, how do you report inability to fulfill   
   >> invariants?  If not, what about RAII -- in this case the   
   >> applicability of RAII suddenly gets *very* narrow.   
      
   > I don't quite follow.   
      
   As noted in another post, RAII is often used as generic scope-guard; a   
   callback to be executed on scope exit.  If we limit us to dtors being   
   used ONLY for operations that "cannot fail", this 'other' use of the   
   RAII idiom is invalid.   
      
   > Is this truely the case? There are several strategies for error   
   > handling in destructors right away, but exceptions aren't. This does   
   > not mean that destructors aren't able to guarantee invariants. Just   
   > that exceptions are not the right mean to deal with problems when   
   > handling with them.   
      
   Of course, but a generic class can't know how to handle the error,   
   which leads us to the solution of subclassing just for the sake of   
   defining destructor behavior in the case of failure.   
      
   > Well, it depends: If I write a file to the system, a possible   
   > solution would be to remove the file in question to ensure that the   
   > user never sees incomplete and potentially corrupt data. When   
   > reading a file, a   
      
   Filesystem may get corrupted so that even remove doesn't succeed.   
      
   > error should be handled in a different way - well, don't put   
   > fclose() into the destructor because then you still *need* the   
   > object to resolve the situation, so closing and destruction are two   
   > different things.   
      
   Agreed, BUT: many textbooks gloss over this issue: they emphasize that   
   it's better to use fstream instead of FILE* also because you can't   
   forget to close the file -- it happens automatically.  So the widely-   
   marketed RAII style of coding   
      
   void f() {   
      fstream f;   
      // closed at scope exit   
   }   
      
   becomes   
      
   void f() {   
      fstream f;   
      try {   
        // some code which may throw   
      } catch(...) {   
        f.close(); // may throw; "forget" the other exception   
   	           // maybe wrap in try-catch and std::terminate?   
   	throw;     // in case close succeeds   
      }   
      f.close(); // duplicated; c++ doesn't have finally{}   
                 // may throw; we don't care   
   }   
      
   > All fine, but if the class is gone, there is nothing to do about it.   
      
   Yes, you can transport relevant data, needed for cleanup, through the   
   exception.   
      
   > Huh? Not at all. Just that the above program is flawed, and the   
   > design isn't right. If you need a strategy for dealing with the   
   > failure, don't put this operation into the destructor - otherwise   
   > the object state for recovery is gone.  Then we're back to something   
   > looking to me worse than the error-code style, see the example   
   > above.   
      
   Then we're back to something looking to me worse than the error-code   
   style, see the example above.   
      
   --   
         [ 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)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca