View mode: basic / threaded / horizontal-split · Log in · Help
January 29, 2008
Newbie initial comments on D language - destructor usage
I have a small nit having to do with a general comment which perhaps I
did not really understand. In the documentation on class destructors I read:

"When the garbage collector calls a destructor for an object of a class
that has members that are references to garbage collected objects, those
references are no longer valid. This means that destructors cannot
reference sub objects. This rule does not apply to auto objects or
objects deleted with the DeleteExpression."

This comment makes perfect sense up to the last sentence. Except for a
'scope' class a destructor can not possibly know how it is being called
so if someone can explain to me how a destructor can know when it is OK
to reference sub-objects or not, I would love to hear about it. I would
have thought that referencing sub-objects in a destructor was just
forbidden unless the class was a 'scope' class and had to reference a
sub-object to possibly release a non-memory resource. But perhaps I am
missing the full meaning of the comment and someone can explicate the
issues involved for me.
January 29, 2008
Re: Newbie initial comments on D language - destructor usage
Edward Diener wrote:
> I have a small nit having to do with a general comment which perhaps I
> did not really understand. In the documentation on class destructors I
> read:
> 
> "When the garbage collector calls a destructor for an object of a class
> that has members that are references to garbage collected objects, those
> references are no longer valid. This means that destructors cannot
> reference sub objects. This rule does not apply to auto objects or
> objects deleted with the DeleteExpression."
> 
> This comment makes perfect sense up to the last sentence. Except for a
> 'scope' class a destructor can not possibly know how it is being called
> so if someone can explain to me how a destructor can know when it is OK
> to reference sub-objects or not, I would love to hear about it.

Under normal circumstances, this is exactly right.  Tango has a feature
whereby the finalization method can be hooked and altered however.  See
slide 18 of this presentation for an example:

http://s3.amazonaws.com/dconf2007/SeanKelly.ppt

> I would
> have thought that referencing sub-objects in a destructor was just
> forbidden unless the class was a 'scope' class and had to reference a
> sub-object to possibly release a non-memory resource. But perhaps I am
> missing the full meaning of the comment and someone can explicate the
> issues involved for me.

In general I think you're right.


Sean
January 29, 2008
Re: Newbie initial comments on D language - destructor usage
Reply to Edward,

> I have a small nit having to do with a general comment which perhaps I
> did not really understand. In the documentation on class destructors I
> read:
> 
> "When the garbage collector calls a destructor for an object of a
> class that has members that are references to garbage collected
> objects, those references are no longer valid. This means that
> destructors cannot reference sub objects. This rule does not apply to
> auto objects or objects deleted with the DeleteExpression."
> 
> This comment makes perfect sense up to the last sentence. Except for a
> 'scope' class a destructor can not possibly know how it is being
> called so if someone can explain to me how a destructor can know when
> it is OK to reference sub-objects or not, I would love to hear about
> it.

Careful use of manual memory management?
January 29, 2008
Re: Newbie initial comments on D language - destructor usage
On Jan 29, 2008 12:52 AM, Edward Diener
<eddielee_no_spam_here@tropicsoft.com> wrote:
> Except for a
> 'scope' class a destructor can not possibly know how it is being called

True.

Nonetheless, I have seen code in C++ which does:

   ~MyHeapClass()
   {
       delete this;
   }

even though the destructor cannot possibly know whether or not the
class was allocated with new. In the C++ case, such code is legitimate
/only/ if the programmer guarantees that MyHeapClass is always
allocated on the heap and never on the stack. (It's a useful thing to
do for thread classes, so that threads can delete themselves without
needing a separate manager class). But of course, there is no way for
the compiler to enforce this. But that's C++ and this is D.
Nonetheless, I think there's an analogy, which is that, if you, the
programmer, /know/ that you are /always/ going to explicitly call
delete, and never rely on the gc to dispose of the class, then you can
make more assumptions about what will still be valid at destructor
time. You are quite right that the compiler has no way to enforce
this, however, so I'd put it down to one of those "exotic" programming
techniques, only ever useful in rare circumstances.

I have never used that feature. If I want my class to have a manual
clean-up function, I'll generally write a function called close().
January 29, 2008
Re: Newbie initial comments on D language - destructor usage
Edward Diener wrote:
> I have a small nit having to do with a general comment which perhaps I
> did not really understand. In the documentation on class destructors I 
> read:
> 
> "When the garbage collector calls a destructor for an object of a class
> that has members that are references to garbage collected objects, those
> references are no longer valid. This means that destructors cannot
> reference sub objects. This rule does not apply to auto objects or
> objects deleted with the DeleteExpression."

> This comment makes perfect sense up to the last sentence. 

You should have seen it before I asked for it to be rewritten!

> Except for a
> 'scope' class a destructor can not possibly know how it is being called
> so if someone can explain to me how a destructor can know when it is OK
> to reference sub-objects or not, I would love to hear about it. I would
> have thought that referencing sub-objects in a destructor was just
> forbidden unless the class was a 'scope' class and had to reference a
> sub-object to possibly release a non-memory resource. But perhaps I am
> missing the full meaning of the comment and someone can explicate the
> issues involved for me.

All it means is that if for whatever reason you _know_ your destructor 
was called explicitly, and not indirectly by the GC, then you're ok. 
Whether this is of any practical use is another matter.  I guess if you 
always hold explicit references to some set of things, then you know the 
GC isn't going to collect them, so you could write those classes to 
refer to stuff in their destructors.  In other words "careful memory 
management" like BCS said so succinctly.

--bb
January 30, 2008
Re: Newbie initial comments on D language - destructor usage
Janice Caron wrote:
> On Jan 29, 2008 12:52 AM, Edward Diener
> <eddielee_no_spam_here@tropicsoft.com> wrote:
>> Except for a
>> 'scope' class a destructor can not possibly know how it is being called
> 
> True.
> 
> Nonetheless, I have seen code in C++ which does:
> 
>     ~MyHeapClass()
>     {
>         delete this;
>     }
> 
> even though the destructor cannot possibly know whether or not the
> class was allocated with new. 

I completely agree the above is bad C++ code, and can only be possibly 
considered correct if some rule says that the class can never be created 
except in dynamic memory. Usually that rule has to do with some C++ 
compiler extension which is not standard C++ and forbids a class object 
to be instantiated on the stack. Such is the case with Microsoft's ATL 
where you will see the idiom above actually occurring in code when the 
reference count for an ActiveX object, which must be created in dynamic 
storage, goes to 0. But in general it is a horrible way of coding.
January 30, 2008
Re: Newbie initial comments on D language - destructor usage
Bill Baxter wrote:
> Edward Diener wrote:
>> I have a small nit having to do with a general comment which perhaps I
>> did not really understand. In the documentation on class destructors I 
>> read:
>>
>> "When the garbage collector calls a destructor for an object of a class
>> that has members that are references to garbage collected objects, those
>> references are no longer valid. This means that destructors cannot
>> reference sub objects. This rule does not apply to auto objects or
>> objects deleted with the DeleteExpression."
> 
>> This comment makes perfect sense up to the last sentence. 
> 
> You should have seen it before I asked for it to be rewritten!

<g>

> 
>> Except for a
>> 'scope' class a destructor can not possibly know how it is being called
>> so if someone can explain to me how a destructor can know when it is OK
>> to reference sub-objects or not, I would love to hear about it. I would
>> have thought that referencing sub-objects in a destructor was just
>> forbidden unless the class was a 'scope' class and had to reference a
>> sub-object to possibly release a non-memory resource. But perhaps I am
>> missing the full meaning of the comment and someone can explicate the
>> issues involved for me.
> 
> All it means is that if for whatever reason you _know_ your destructor 
> was called explicitly, and not indirectly by the GC, then you're ok. 
> Whether this is of any practical use is another matter.  I guess if you 
> always hold explicit references to some set of things, then you know the 
> GC isn't going to collect them, so you could write those classes to 
> refer to stuff in their destructors.  In other words "careful memory 
> management" like BCS said so succinctly.

What is an 'explicit reference to some set of things' ? Can not the GC 
be destroying your object in a cross-reference situation where the 
references you hold are no longer guaranteed to exist in the destructor  ?
January 30, 2008
Re: Newbie initial comments on D language - destructor usage
Edward Diener wrote:
> Bill Baxter wrote:
>> Edward Diener wrote:
>>> I have a small nit having to do with a general comment which perhaps I
>>> did not really understand. In the documentation on class destructors 
>>> I read:
>>>
>>> "When the garbage collector calls a destructor for an object of a class
>>> that has members that are references to garbage collected objects, those
>>> references are no longer valid. This means that destructors cannot
>>> reference sub objects. This rule does not apply to auto objects or
>>> objects deleted with the DeleteExpression."
>>
>>> This comment makes perfect sense up to the last sentence. 
>>
>> You should have seen it before I asked for it to be rewritten!
> 
> <g>
> 
>>
>>> Except for a
>>> 'scope' class a destructor can not possibly know how it is being called
>>> so if someone can explain to me how a destructor can know when it is OK
>>> to reference sub-objects or not, I would love to hear about it. I would
>>> have thought that referencing sub-objects in a destructor was just
>>> forbidden unless the class was a 'scope' class and had to reference a
>>> sub-object to possibly release a non-memory resource. But perhaps I am
>>> missing the full meaning of the comment and someone can explicate the
>>> issues involved for me.
>>
>> All it means is that if for whatever reason you _know_ your destructor 
>> was called explicitly, and not indirectly by the GC, then you're ok. 
>> Whether this is of any practical use is another matter.  I guess if 
>> you always hold explicit references to some set of things, then you 
>> know the GC isn't going to collect them, so you could write those 
>> classes to refer to stuff in their destructors.  In other words 
>> "careful memory management" like BCS said so succinctly.
> 
> What is an 'explicit reference to some set of things' ? Can not the GC 
> be destroying your object in a cross-reference situation where the 
> references you hold are no longer guaranteed to exist in the destructor  ?

Sure, I'm just saying if you're very careful about who holds references 
to what then you can guarantee the GC won't clean it up.

class MyClass {
   this(MyOtherClass c) { c_ = c; }
   ~this() { c_.do_something_fun(); }
}
MyOtherClass c;
MyClass d;

void main() {

   c = new MyOtherClass;
   d = new MyClass(c);

   delete d;
}

In this program it is ok for MyClass to be using its c_ in its 
destructor.  There's no way for c_ to have been destroyed already when 
we get to d's constructor *in this program*.

I think this is probably of little practical value, though.  I think all 
Walter wants to say there is that the indeterminate order of destruction 
in a GC world is the only reason why you can't refer to things in your 
destructors.  Other than that, destructors work in a normal 
deterministic C++-ish way.

--bb
January 30, 2008
Re: Newbie initial comments on D language - destructor usage
Edward Diener wrote:
> Janice Caron wrote:
>> On Jan 29, 2008 12:52 AM, Edward Diener
>> <eddielee_no_spam_here@tropicsoft.com> wrote:
>>> Except for a
>>> 'scope' class a destructor can not possibly know how it is being called
>>
>> True.
>>
>> Nonetheless, I have seen code in C++ which does:
>>
>>     ~MyHeapClass()
>>     {
>>         delete this;
>>     }
>>
>> even though the destructor cannot possibly know whether or not the
>> class was allocated with new. 
> 
> I completely agree the above is bad C++ code, and can only be possibly 
> considered correct if some rule says that the class can never be created 
> except in dynamic memory. 

Not even then; "delete this" is not valid from within a destructor,
as the destructor has already set about destroying the object, and
so attempting to re-destroy the object makes no sense.

It's safe to use "delete this" in response to an object being told
to drop the last reference to itself, but it makes no sense to do
so from its own destructor.

I suspect Janice just mis-quoted some C++ code, moving "delete this"
to somewhere it doesn't belong.

-- James
January 30, 2008
Re: Newbie initial comments on D language - destructor usage
On 1/30/08, James Dennett <jdennett@acm.org> wrote:
> I suspect Janice just mis-quoted some C++ code, moving "delete this"
> to somewhere it doesn't belong.

Nah, I just misremember it. It should of course be

   ~MyHeapClass()
    {
       operator delete(this);
   }

That does the memory deallocation without re-calling the destructor. :-)
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home