Jump to page: 1 2
Thread overview
Destructing Member Objects
Apr 05, 2008
Brian White
Apr 05, 2008
Lionello Lunesu
Apr 06, 2008
Simen Kjaeraas
Apr 07, 2008
Christopher Wright
Apr 07, 2008
Simen Kjaeraas
Apr 08, 2008
Lionello Lunesu
Apr 06, 2008
Simen Kjaeraas
Apr 06, 2008
Brian White
April 05, 2008
I understand that you're not supposed to delete member within the destructor because, when called via the GC, it's possible that object has already been destructed.

Is there a way for the object to determine if it's being destructed as part of a GC run or if it's being deleted explicitly?

-- Brian
April 05, 2008
"Brian White" <bcwhite@pobox.com> wrote in message news:ft8iuk$qvm$1@digitalmars.com...
>I understand that you're not supposed to delete member within the destructor because, when called via the GC, it's possible that object has already been destructed.
>
> Is there a way for the object to determine if it's being destructed as part of a GC run or if it's being deleted explicitly?
>
> -- Brian

Suggested, lauded, unread, forgotten.

Just like most proposed features for D.


April 05, 2008
Brian White wrote:
> I understand that you're not supposed to delete member within the destructor because, when called via the GC, it's possible that object has already been destructed.

:O really? Where can I find more information about this?

I think it's odd that a member can get deleted before a class that contains it. That class still has a valid pointer to it, right? So the GC could not have finalized it.. ???

L.
April 06, 2008
On Sat, 05 Apr 2008 21:12:18 +0200, Brian White <bcwhite@pobox.com> wrote:

> I understand that you're not supposed to delete member within the destructor because, when called via the GC, it's possible that object has already been destructed.
>
> Is there a way for the object to determine if it's being destructed as part of a GC run or if it's being deleted explicitly?
>
> -- Brian


class foo
{
  private ~this()
  {
  }

  public kill()
  {
  // call any specific code you want here
  delete this;
  }
}

Then use foo.kill() instead of delete foo. Ugly, but works, I think.
April 06, 2008
"Lionello Lunesu" <lio@lunesu.remove.com> wrote in message news:ft9350$23n8$1@digitalmars.com...
> Brian White wrote:
>> I understand that you're not supposed to delete member within the destructor because, when called via the GC, it's possible that object has already been destructed.
>
> :O really? Where can I find more information about this?
>
> I think it's odd that a member can get deleted before a class that contains it. That class still has a valid pointer to it, right? So the GC could not have finalized it.. ???
>
> L.

http://www.digitalmars.com/d/1.0/class.html#destructors

"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 is because that the garbage collector does not collect objects in any guaranteed order, so there is no guarantee that any pointers or references to any other garbage collected objects exist when the garbage collector runs the destructor for an object. This rule does not apply to auto objects or objects deleted with the DeleteExpression, as the destructor is not being run by the garbage collector, meaning all references are valid."

The spec doesn't really specify _why_ destruction order is nondeterministic, however.  You need nondeterministic destruction in order to break cycles. So if A points to B and B points to A, you have a cycle.  In order to break the cycle you have to delete one or the other first.  There's no "correct" order to destroy them.  So, to solve this, you simply cannot guarantee that when an object's destructor is run, that everything that it points to is still valid.

(Note, however, that system resources (file handles, Windows COM interfaces, sockets, things like that) _can_ be referenced since they weren't allocated on the GC heap.  The only problem there is _when_ they're referenced, since there's no guarantee that the object containing the reference to the system resource will be collected in any timely fashion.)


April 06, 2008
> class foo
> {
>   private ~this()
>   {
>   }
> 
>   public kill()
>   {
>   // call any specific code you want here
>   delete this;
>   }
> }
> 
> Then use foo.kill() instead of delete foo. Ugly, but works, I think.

I don't think it does work.  If you have a "scope" variable, for example, the compiler won't call "kill" when deleting the object.

-- Brian
April 06, 2008
On Sun, 06 Apr 2008 06:27:52 +0200, Jarrett Billingsley <kb3ctd2@yahoo.com> wrote:

> The spec doesn't really specify _why_ destruction order is nondeterministic,
> however.  You need nondeterministic destruction in order to break cycles.
> So if A points to B and B points to A, you have a cycle.  In order to break
> the cycle you have to delete one or the other first.  There's no "correct"
> order to destroy them.  So, to solve this, you simply cannot guarantee that
> when an object's destructor is run, that everything that it points to is
> still valid.

It's worth noting that even if only one object in a relation points to
another (i.e. no cycle), the easiest thing for the GC to do is to flag both
as trash, then destroy them in some order when it gets to that point. If it
were to flag only the mother class and destroy that, its child classes might
have to wait until the next GC run before they're deleted.

-- Simen
April 06, 2008
"Brian White" <bcwhite@pobox.com> wrote in message news:ft9oil$j0a$1@digitalmars.com...
>> class foo
>> {
>>   private ~this()
>>   {
>>   }
>>
>>   public kill()
>>   {
>>   // call any specific code you want here
>>   delete this;
>>   }
>> }
>>
>> Then use foo.kill() instead of delete foo. Ugly, but works, I think.
>
> I don't think it does work.  If you have a "scope" variable, for example, the compiler won't call "kill" when deleting the object.

You'd have to do it yourself.

{
    auto f = new foo();
    scope(exit) f.kill();

    // ...
}


April 07, 2008
Simen Kjaeraas wrote:
> On Sun, 06 Apr 2008 06:27:52 +0200, Jarrett Billingsley <kb3ctd2@yahoo.com> wrote:
> 
>> The spec doesn't really specify _why_ destruction order is nondeterministic,
>> however.  You need nondeterministic destruction in order to break cycles.
>> So if A points to B and B points to A, you have a cycle.  In order to break
>> the cycle you have to delete one or the other first.  There's no "correct"
>> order to destroy them.  So, to solve this, you simply cannot guarantee that
>> when an object's destructor is run, that everything that it points to is
>> still valid.
> 
> It's worth noting that even if only one object in a relation points to
> another (i.e. no cycle), the easiest thing for the GC to do is to flag both
> as trash, then destroy them in some order when it gets to that point. If it
> were to flag only the mother class and destroy that, its child classes might
> have to wait until the next GC run before they're deleted.
> 
> -- Simen

That doesn't work. The collector flags stuff only as not-trash, never as trash. Then it does a linear scan through each block containing aggregate types and calls destructors.

Well, maybe not, but that's how I'd implement it, if I cared about efficiency.
April 07, 2008
On Mon, 07 Apr 2008 03:46:31 +0200, Christopher Wright <dhasenan@gmail.com> wrote:

> Simen Kjaeraas wrote:
>> On Sun, 06 Apr 2008 06:27:52 +0200, Jarrett Billingsley <kb3ctd2@yahoo.com> wrote:
>>
>>> The spec doesn't really specify _why_ destruction order is nondeterministic,
>>> however.  You need nondeterministic destruction in order to break cycles.
>>> So if A points to B and B points to A, you have a cycle.  In order to break
>>> the cycle you have to delete one or the other first.  There's no "correct"
>>> order to destroy them.  So, to solve this, you simply cannot guarantee that
>>> when an object's destructor is run, that everything that it points to is
>>> still valid.
>>  It's worth noting that even if only one object in a relation points to
>> another (i.e. no cycle), the easiest thing for the GC to do is to flag both
>> as trash, then destroy them in some order when it gets to that point. If it
>> were to flag only the mother class and destroy that, its child classes might
>> have to wait until the next GC run before they're deleted.
>>  -- Simen
>
> That doesn't work. The collector flags stuff only as not-trash, never as trash. Then it does a linear scan through each block containing aggregate types and calls destructors.
>
> Well, maybe not, but that's how I'd implement it, if I cared about efficiency.

You're probably right. My point was only that even if there is no circular
reference, there's still a reason to have nondeterministic destruction.
« First   ‹ Prev
1 2