May 02, 2007 Re: destructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Giddings | Daniel Giddings wrote:
> Daniel Keep wrote:
>>
>>
>> Exactly. You can't.
>>
>> Long story short is thus: the *only* thing you can say for sure still
>> exists when your destructor is called, is your own object's memory.
>
> Yuck - I never really thought about this. So destructors in D are almost as useless as the __del__ method in Python :-(
>
>> Question: what order do the objects get destroyed in?
>> Answer: no one knows.
>>
>> The problem is that in order for the GC to destroy objects in "the right
>> order", it would have to build a complete dependency graph between the
>> various objects, then destroy them in the right order.
>>
>> But what happens if you've got a *lot* of objects, or those objects
>> don't care what order they're destroyed in, or worse: cycles. If you've
>> got cycles, the GC is stuffed, and there *is* no correct order to
>> destroy them in.
>>
>> There was a thread quite some time ago that demonstrated a hacked
>> version of phobos that allowed destructors to take a bool argument that
>> told the destructor if the object was being destroyed deterministically
>> (ie: via the delete statement, or because the object was scoped) or not.
>> Sadly, it never caught on :(
>>
>> -- Daniel
>>
>
> The bool would be incredibly handy as you'd be able to still do destructor type things safely with explicit deletes.
>
> I suppose an alternative would be something like
>
> class MyClass
> {
> OtherClass a;
> this() { a = new OtherClass; }
> MyClass destroy() { delete a; delete this; return null; }
> // is the return null above ok in D? - it seemed ok when run
> }
>
> then you'd know when its been explicitly deleted.
>
> MyClass m = new MyClass;
> ...
> m = m.destroy();
I was thinking that too. That might be ok for some use cases, but it doesn't help with 'scope' instances (the destructor will get called not your 'destroy()' method). And in generic cases, like a tuple of objects you want to destroy, the generic function has no way of knowing that it should call 'obj.destroy()' on some objects instead of 'delete obj'.
--bb
|
May 02, 2007 Re: destructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Giddings | Daniel Giddings wrote: > Daniel Keep wrote: >> >> >> Exactly. You can't. >> >> Long story short is thus: the *only* thing you can say for sure still exists when your destructor is called, is your own object's memory. > > Yuck - I never really thought about this. So destructors in D are almost as useless as the __del__ method in Python :-( > >> Question: what order do the objects get destroyed in? Answer: no one knows. >> >> The problem is that in order for the GC to destroy objects in "the right order", it would have to build a complete dependency graph between the various objects, then destroy them in the right order. >> >> But what happens if you've got a *lot* of objects, or those objects don't care what order they're destroyed in, or worse: cycles. If you've got cycles, the GC is stuffed, and there *is* no correct order to destroy them in. >> >> There was a thread quite some time ago that demonstrated a hacked >> version of phobos that allowed destructors to take a bool argument that >> told the destructor if the object was being destroyed deterministically >> (ie: via the delete statement, or because the object was scoped) or not. >> Sadly, it never caught on :( >> >> -- Daniel >> > > The bool would be incredibly handy as you'd be able to still do destructor type things safely with explicit deletes. > > I suppose an alternative would be something like > > class MyClass > { > OtherClass a; > this() { a = new OtherClass; } > MyClass destroy() { delete a; delete this; return null; } > // is the return null above ok in D? - it seemed ok when run > } > > then you'd know when its been explicitly deleted. > > MyClass m = new MyClass; > .... > m = m.destroy(); The other thing I started doing in some of my code was to use the following: interface Disposable { void dispose(); } void dispose(Object obj) { if( auto dobj = cast(Disposable)obj ) dobj.dispose(); } Yes, you have to do it manually, but at least you can do it *safely*. I think Tango has something similar :P -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/ |
May 02, 2007 Re: destructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | Daniel Keep wrote:
>
> Daniel Giddings wrote:
>> Daniel Keep wrote:
> The other thing I started doing in some of my code was to use the following:
>
> interface Disposable
> {
> void dispose();
> }
>
> void dispose(Object obj)
> {
> if( auto dobj = cast(Disposable)obj )
> dobj.dispose();
> }
Why not follow up the call to dispose with a 'delete dobj'?
Would that make 'scope' fail?
--bb
|
May 02, 2007 Re: destructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bill Baxter | Bill Baxter wrote:
>
> I was thinking that too. That might be ok for some use cases, but it doesn't help with 'scope' instances (the destructor will get called not your 'destroy()' method). And in generic cases, like a tuple of objects you want to destroy, the generic function has no way of knowing that it should call 'obj.destroy()' on some objects instead of 'delete obj'.
>
>
> --bb
With a small change you could catch those cases, but it is starting to get a bit messy.
class MyClass
{
OtherClass a;
bool destroyed = false;
this() { a = new OtherClass; }
~this() { if( !destroyed ) throw new Exception( "~this without .destroy" ); }
MyClass destroy() { delete a; destroyed = true; delete this; return null; }
}
:-) Dan
|
May 02, 2007 Re: destructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Giddings | Daniel Giddings wrote: > Bill Baxter wrote: >> >> I was thinking that too. That might be ok for some use cases, but it doesn't help with 'scope' instances (the destructor will get called not your 'destroy()' method). And in generic cases, like a tuple of objects you want to destroy, the generic function has no way of knowing that it should call 'obj.destroy()' on some objects instead of 'delete obj'. >> >> >> --bb > > With a small change you could catch those cases, but it is starting to get a bit messy. > > class MyClass > { > OtherClass a; > bool destroyed = false; > this() { a = new OtherClass; } > ~this() { if( !destroyed ) throw new Exception( "~this without > ..destroy" ); } > MyClass destroy() { delete a; destroyed = true; delete this; return > null; } > } > > :-) Dan I thought exceptions thrown in a destructor got ignored? -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/ |
May 02, 2007 Re: destructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bill Baxter | Bill Baxter wrote: > Daniel Keep wrote: >> >> Daniel Giddings wrote: >>> Daniel Keep wrote: >> The other thing I started doing in some of my code was to use the following: >> >> interface Disposable >> { >> void dispose(); >> } >> >> void dispose(Object obj) >> { >> if( auto dobj = cast(Disposable)obj ) >> dobj.dispose(); >> } > > Why not follow up the call to dispose with a 'delete dobj'? Would that make 'scope' fail? > > > --bb Then you'd get a double-free, so I think it might. I actually forgot about the *other* function I use: void destroy(inout Object obj) { dispose(obj); delete obj; } So you can destroy heap allocated objects, and just dispose scoped ones. -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/ |
May 02, 2007 Re: destructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | >
> I thought exceptions thrown in a destructor got ignored?
>
> -- Daniel
>
The test below gives the following result:
this
~this
Error: ~this without .destroy
at least with dmd 1.007 in windows...
:-) Dan
--
import std.stdio;
class OtherClass
{
this() { writefln( "this" ); }
~this() { writefln( "~this" ); }
}
class MyClass
{
OtherClass a;
bool destroyed = false;
this() { a = new OtherClass; }
~this() { if( !destroyed ) throw new Exception( "~this without .destroy" ); }
MyClass destroy() { delete a; destroyed = true; delete this; return null; }
}
void main()
{
MyClass m = new MyClass;
}
|
May 03, 2007 Re: destructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jarrett Billingsley | Jarrett Billingsley wrote: > "Bill Baxter" <dnewsgroup@billbaxter.com> wrote in message news:f17iv3$1s1a$1@digitalmars.com... >> Ok, so we can say that generally speaking, any D code that contains a 'delete member;' in the destructor is bad code. Right? > > Any destructor which uses any reference members in any way is bad code. Why so? If a reference member is manually memory-managed, it's quite ok (and expected) to have it being deleted in the constructor, no? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D |
May 03, 2007 Re: destructors | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruno Medeiros | "Bruno Medeiros" <brunodomedeiros+spam@com.gmail> wrote in message news:f1ceq9$1o79$1@digitalmars.com... > > Why so? If a reference member is manually memory-managed, it's quite ok (and expected) to have it being deleted in the constructor, no? > Yes, that's true. |
Copyright © 1999-2021 by the D Language Foundation