From: Sean O'Dell Date: 2002-02-25T06:22:39+09:00 Subject: Re: Object/Memory Management "Sean Middleditch" wrote in message news:1014582552.13608.4.camel@stargrazer... > On Sun, 2002-02-24 at 15:05, Jim Weirich wrote: > > >>>>> "SeanM" == Sean Middleditch writes: > > > > SeanM> [...] The stack does *not* in any way guarantee that those > > SeanM> objects are cleaned up. You can leave functions without > > SeanM> cleaning up (destroying) objects on the stack. Errors or > > SeanM> exceptions can occur during stack cleanup that you can't > > SeanM> catch or deal with. The order of object destruction is (in > > SeanM> many compilers) not guaranteed. [...] > > > > Actually, if we are talking about stack based C++ objects here, this > > is incorrect. The order of destruction of stack based objects is > > always reverse order of creation. They are guaranteed to be > > destructed upon leaving the scope of the function, even in the > > presence of exceptions (setjump/longjump does cause problems). > > Jumping was the one issue I was referring. The order of destructors, > while supposedly a standard, doesn't work on all C++ compilers. > Thankfully, the major players (VC++, GCC, Borland C++, Watcom C++) all > work right in this regard. Yes, but there are bad implementations everywhere. Don't avoid something because someone's compiler somewhere might not do something quite right. > > Since C++ doesn't have a finally statement, or easy to use closures, > > the stack based destructor trick is used pervasively. Many C++ > > programmers try to take this technique with them when trying other > > languages. Unfortunately, I've only seen it work effectively in C++ > > The stack based destructor still falls apart too easily, especially when > errors occur in the destructor. This much is true. Generally speaking, though, if a destructor needs to do something of any complication, I stick it in a block with not much else. Actually, if I have such activity in a destructor, I make the complicated call myself, but the destructor is there to *try* and make sure it happens in case someone forgot to make the call. Here's a great example of what destructors are good for that won't invoke the "exception during destruction" issue. A hierarchy of objects. Say I have a parent object with several child objects. Each child object has a pointer back to its parent, and the parent has pointers to its children. The outside world never sees the pointers, but will ask the parent to give a reference to a child, and the child for its parent. If a child object goes away for some reason, the destructor makes a simple call back to the parent telling it to clear its pointer because its leaving. There's zero chance an error will occur, but it's ABSOLUTELY CRITICAL that the parent know the child is leaving. Now, I know in Ruby you don't have pointers. The child object will forever belong to the parent so long as the parent references the child, which it likely will unless you deliberately remove the reference. So, for Ruby, this isn't a good analogy. And that may be what it is about Ruby. You just don't need those destructors as much. But in C++, they're oftentimes essential. Sean