Jump to page: 1 2
Thread overview
Newbie initial comments on D language - destructor usage
Jan 29, 2008
Edward Diener
Jan 29, 2008
Sean Kelly
Jan 29, 2008
BCS
Jan 29, 2008
Janice Caron
Jan 30, 2008
Edward Diener
Jan 30, 2008
James Dennett
Jan 30, 2008
Janice Caron
Jan 30, 2008
Janice Caron
Jan 30, 2008
Edward Diener
Jan 29, 2008
Bill Baxter
Jan 30, 2008
Edward Diener
Jan 30, 2008
Bill Baxter
January 29, 2008
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
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
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
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
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
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
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
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
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
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