digitalmars.D.learn - destructors
- Bill Baxter (14/14) May 01 2007 Is this ok in D?
- Daniel Keep (17/35) May 01 2007 I'd be suspect of the delete; unless you explicitly delete an object,
-
Jarrett Billingsley
(4/6)
May 01 2007
-
Daniel Keep
(13/21)
May 01 2007
- Daniel Giddings (9/27) May 01 2007 I would expect that to work (it is something I would want to be able to
- Daniel Keep (29/69) May 01 2007 Exactly. You can't.
- Sean Kelly (4/10) May 01 2007 Tango provides a global hook for this. It isn't exactly the same, but
- Bill Baxter (13/81) May 01 2007 That makes a lot of sense. Why can't it just say that in the
- Jarrett Billingsley (6/8) May 01 2007 Any destructor which uses any reference members in any way is bad code.
- Bruno Medeiros (6/12) May 03 2007 Why so? If a reference member is manually memory-managed, it's quite ok
- Jarrett Billingsley (3/5) May 03 2007 Yes, that's true.
- Daniel Giddings (17/43) May 01 2007 Yuck - I never really thought about this. So destructors in D are almost...
- Bill Baxter (7/57) May 01 2007 I was thinking that too. That might be ok for some use cases, but it
- Daniel Giddings (13/22) May 01 2007 With a small change you could catch those cases, but it is starting to
- Daniel Keep (12/39) May 01 2007 I thought exceptions thrown in a destructor got ignored?
- Daniel Giddings (26/31) May 01 2007 The test below gives the following result:
- Daniel Keep (23/73) May 01 2007 The other thing I started doing in some of my code was to use the follow...
- Bill Baxter (4/19) May 01 2007 Why not follow up the call to dispose with a 'delete dobj'?
- Daniel Keep (19/42) May 01 2007 Then you'd get a double-free, so I think it might. I actually forgot
Is this ok in D? class MyClass { OtherClass a; this() { a = new OtherClass; } ~this() { delete a; } } I was just trying to fix the crash on exit in the tinyXPath code on dsource, and it does the above a lot. --bb
May 01 2007
Bill Baxter wrote:Is this ok in D? class MyClass { OtherClass a; this() { a = new OtherClass; } ~this() { delete a; } } I was just trying to fix the crash on exit in the tinyXPath code on dsource, and it does the above a lot. --bbI'd be suspect of the delete; unless you explicitly delete an object, you cannot guarantee in what order objects will be destroyed. That means that it's entirely possible that 'a' has already been deleted by the time your dtor runs. <Insert song and dance about how having an implicit/explicit flag passed to dtors would solve this.> -- 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 01 2007
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message news:f171sp$104t$1 digitalmars.com...<Insert song and dance about how having an implicit/explicit flag passed to dtors would solve this.><Insert song and dance about how having an explicit destruction order would solve this even easier>
May 01 2007
Jarrett Billingsley wrote:"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message news:f171sp$104t$1 digitalmars.com...<Via the majesty of interpretive dance, point out that having potential cycles of objects makes that really, really difficult, but that having any kind of solution would be an improvement> -- 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/<Insert song and dance about how having an implicit/explicit flag passed to dtors would solve this.><Insert song and dance about how having an explicit destruction order would solve this even easier>
May 01 2007
Bill Baxter wrote:Is this ok in D? class MyClass { OtherClass a; this() { a = new OtherClass; } ~this() { delete a; } } I was just trying to fix the crash on exit in the tinyXPath code on dsource, and it does the above a lot. --bbI would expect that to work (it is something I would want to be able to do - otherwise you would need a finalise method - yuck), I can't recall if I have done it though? a should still be detected as having objects referencing it until the MyClass destructor is finished I would think (if the delete a wasn't there). Otherwise you would not be able to rely on any class properties as still existing in its destructor (ie a.method() could cause an exception as well).
May 01 2007
Daniel Giddings wrote:Bill Baxter 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. Look at it like this:Is this ok in D? class MyClass { OtherClass a; this() { a = new OtherClass; } ~this() { delete a; } } I was just trying to fix the crash on exit in the tinyXPath code on dsource, and it does the above a lot. --bbI would expect that to work (it is something I would want to be able to do - otherwise you would need a finalise method - yuck), I can't recall if I have done it though? a should still be detected as having objects referencing it until the MyClass destructor is finished I would think (if the delete a wasn't there). Otherwise you would not be able to rely on any class properties as still existing in its destructor (ie a.method() could cause an exception as well).class ObjPtr { ObjPtr obj; this(ObjPtr obj = null) { this.obj = obj; } ~this() { ... } } auto a = new ObjPtr; auto b = new ObjPtr(a); auto c = new ObjPtr(b); c = null; gc.fullCollect();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 -- 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 01 2007
Daniel Keep wrote: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 :(Tango provides a global hook for this. It isn't exactly the same, but it has a similar effect. Sean
May 01 2007
Daniel Keep wrote:Daniel Giddings wrote:That makes a lot of sense. Why can't it just say that in the documentation? "In the presenence of cycles, it is impossible to ensure that parent objects are always deleted before the children they refer to." Ok, so we can say that generally speaking, any D code that contains a 'delete member;' in the destructor is bad code. Right? The exceptions mentioned in the doc are scope classes (well the doc says "auto" but I think it means old-school auto, aka "scope", because you know that's not going away because of a GC sweep.). And also anything else you know is getting explicitly deleted is ok... except there's no way to *know* if you're being explicitly deleted so you have to assume you're not. --bbBill Baxter 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. Look at it like this:Is this ok in D? class MyClass { OtherClass a; this() { a = new OtherClass; } ~this() { delete a; } } I was just trying to fix the crash on exit in the tinyXPath code on dsource, and it does the above a lot. --bbI would expect that to work (it is something I would want to be able to do - otherwise you would need a finalise method - yuck), I can't recall if I have done it though? a should still be detected as having objects referencing it until the MyClass destructor is finished I would think (if the delete a wasn't there). Otherwise you would not be able to rely on any class properties as still existing in its destructor (ie a.method() could cause an exception as well).class ObjPtr { ObjPtr obj; this(ObjPtr obj = null) { this.obj = obj; } ~this() { ... } } auto a = new ObjPtr; auto b = new ObjPtr(a); auto c = new ObjPtr(b); c = null; gc.fullCollect();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 :(
May 01 2007
"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. Thus making destructors nearly worthless for anything but releasing system resources. But even then, I'm not sure if the destructors always get called, especially at the end of the program.
May 01 2007
Jarrett Billingsley wrote:"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:f17iv3$1s1a$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? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DOk, 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.
May 03 2007
"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.
May 03 2007
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 :( -- DanielThe 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();
May 01 2007
Daniel Giddings wrote:Daniel Keep 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'. --bbExactly. 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 :( -- DanielThe 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();
May 01 2007
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'. --bbWith 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 01 2007
Daniel Giddings wrote:Bill Baxter wrote: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/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'. --bbWith 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 01 2007
I thought exceptions thrown in a destructor got ignored? -- DanielThe 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 01 2007
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(); } 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/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 :( -- DanielThe 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();
May 01 2007
Daniel Keep wrote:Daniel Giddings wrote:Why not follow up the call to dispose with a 'delete dobj'? Would that make 'scope' fail? --bbDaniel 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(); }
May 01 2007
Bill Baxter wrote:Daniel Keep wrote: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/Daniel Giddings wrote:Why not follow up the call to dispose with a 'delete dobj'? Would that make 'scope' fail? --bbDaniel 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(); }
May 01 2007