Thread overview | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
April 05, 2008 Destructing Member Objects | ||||
---|---|---|---|---|
| ||||
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 Re: Destructing Member Objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to Brian White | "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 Re: Destructing Member Objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to Brian White | 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 Re: Destructing Member Objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to Brian White | 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 Re: Destructing Member Objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to Lionello Lunesu | "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 Re: Destructing Member Objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjaeraas | > 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 Re: Destructing Member Objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jarrett Billingsley | 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 Re: Destructing Member Objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to Brian White | "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 Re: Destructing Member Objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjaeraas | 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 Re: Destructing Member Objects | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christopher Wright | 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.
|
Copyright © 1999-2021 by the D Language Foundation