www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - destructors and GC again

reply Lutger <lutger.blijdestijn gmail.com> writes:
Sorry for this topic again, I'm still not exactly sure: when an 
unreferenced object is collected during the lifetime of your program 
(before main exits), is the destructor of this object guaranteed to be 
called? I expect it to be so, as otherwise destructors seem pretty 
useless (and dangerous), but cannot infer this from the spec.

The spec says: "The garbage collector is not guaranteed to run the 
destructor for all unreferenced objects ... The garbage collector calls 
the destructor function when the object is deleted."

It's not clear from this to me that IF an object is collected (of which 
you cannot be sure, ok), what is guaranteed about the destructor. I 
assume 'deleted' in the spec means that delete is explicitly called, not 
'collected by the GC'.
Oct 16 2006
next sibling parent reply Derek Parnell <derek psyc.ward> writes:
On Mon, 16 Oct 2006 16:36:52 +0200, Lutger wrote:

 Sorry for this topic again, I'm still not exactly sure: when an 
 unreferenced object is collected during the lifetime of your program 
 (before main exits), is the destructor of this object guaranteed to be 
 called? I expect it to be so, as otherwise destructors seem pretty 
 useless (and dangerous), but cannot infer this from the spec.
 
 The spec says: "The garbage collector is not guaranteed to run the 
 destructor for all unreferenced objects ... The garbage collector calls 
 the destructor function when the object is deleted."
 
 It's not clear from this to me that IF an object is collected (of which 
 you cannot be sure, ok), what is guaranteed about the destructor. I 
 assume 'deleted' in the spec means that delete is explicitly called, not 
 'collected by the GC'.

I don't think that it is guaranteed. You need to either explicitly delete it or use 'auto' (meaning RAII this time). e.g. void somefunc() { auto MyClass X = new MyClass(); } or void somefunc() { MyClass X = new MyClass(); scope(exit) { delete X; } } -- Derek Parnell Melbourne, Australia "Down with mediocrity!"
Oct 16 2006
parent Lutger <lutger.blijdestijn gmail.com> writes:
Derek Parnell wrote:
 On Mon, 16 Oct 2006 16:36:52 +0200, Lutger wrote:
 
 Sorry for this topic again, I'm still not exactly sure: when an 
 unreferenced object is collected during the lifetime of your program 
 (before main exits), is the destructor of this object guaranteed to be 
 called? I expect it to be so, as otherwise destructors seem pretty 
 useless (and dangerous), but cannot infer this from the spec.

 The spec says: "The garbage collector is not guaranteed to run the 
 destructor for all unreferenced objects ... The garbage collector calls 
 the destructor function when the object is deleted."

 It's not clear from this to me that IF an object is collected (of which 
 you cannot be sure, ok), what is guaranteed about the destructor. I 
 assume 'deleted' in the spec means that delete is explicitly called, not 
 'collected by the GC'.

I don't think that it is guaranteed. You need to either explicitly delete it or use 'auto' (meaning RAII this time). e.g. void somefunc() { auto MyClass X = new MyClass(); } or void somefunc() { MyClass X = new MyClass(); scope(exit) { delete X; } }

Really? That would be so foobar. I'm trying to rewrite my half-broken signal-slots lib, the C-heap hack I have figured out. (Cannot use auto for this). But I think I need such a guarantee for destructors. This is sort of what I want to achieve: 1. Store a delegate from a member function in C-heap to be used as a callback, so this callback won't prevent GC from collecting the object the callback is taken from. 2. At some point this object is collected by GC. 3. Now the stored callback should be removed, otherwise invoking the callback later in time is a no-no of course. This is done from the destructor of the collected object. If 3) is not guaranteed to occur (before main exits, after that it doesn't matter), then I don't see a way to garbage collect these callbacks, which leaves me with the following options: a) don't use the C-heap and just leak memory which the user must manually clean up. b) rely on the user to call delete, avoiding GC altogether. (not a good idea) Both options are not very satisfying, and perhaps even defy the point of such a library. Maybe I'm missing something here?
Oct 16 2006
prev sibling parent reply Sean Kelly <sean f4.ca> writes:
Lutger wrote:
 Sorry for this topic again, I'm still not exactly sure: when an 
 unreferenced object is collected during the lifetime of your program 
 (before main exits), is the destructor of this object guaranteed to be 
 called? I expect it to be so, as otherwise destructors seem pretty 
 useless (and dangerous), but cannot infer this from the spec.

When an object is collected by the GC, it's dtor will be called. However, the GC may not detect an orphaned object as collectable if there is a value in memory somewhere that "looks" like a reference to that object. Sean
Oct 16 2006
next sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
Sean Kelly wrote:
 Lutger wrote:
 Sorry for this topic again, I'm still not exactly sure: when an 
 unreferenced object is collected during the lifetime of your program 
 (before main exits), is the destructor of this object guaranteed to be 
 called? I expect it to be so, as otherwise destructors seem pretty 
 useless (and dangerous), but cannot infer this from the spec.

When an object is collected by the GC, it's dtor will be called. However, the GC may not detect an orphaned object as collectable if there is a value in memory somewhere that "looks" like a reference to that object. Sean

Good, the possibly not collecting part is no problem. It would make more sense to me if these sentences in the spec were different: Spec: "The garbage collector is not guaranteed to run the destructor for all unreferenced objects" My interpretation: "The garbage collector is not guaranteed to collect all unreferenced objects" Spec: "The garbage collector calls the destructor function when the object is deleted." My interpretation: "The garbage collector calls the destructor function when the object is collected."
Oct 16 2006
prev sibling parent reply Carlos Santander <csantander619 gmail.com> writes:
Sean Kelly escribió:
 Lutger wrote:
 Sorry for this topic again, I'm still not exactly sure: when an 
 unreferenced object is collected during the lifetime of your program 
 (before main exits), is the destructor of this object guaranteed to be 
 called? I expect it to be so, as otherwise destructors seem pretty 
 useless (and dangerous), but cannot infer this from the spec.

When an object is collected by the GC, it's dtor will be called. However, the GC may not detect an orphaned object as collectable if there is a value in memory somewhere that "looks" like a reference to that object. Sean

There's also the problem with global objects: //------------------------------------------- import std.stdio; class A { ~this() { writefln("~A"); } } A tmp; void main() { tmp=new A; } //------------------------------------------- Nothing is printed. -- Carlos Santander Bernal
Oct 16 2006
parent reply Derek Parnell <derek psyc.ward> writes:
On Mon, 16 Oct 2006 15:34:22 -0500, Carlos Santander wrote:

 Sean Kelly escribió:
 Lutger wrote:
 Sorry for this topic again, I'm still not exactly sure: when an 
 unreferenced object is collected during the lifetime of your program 
 (before main exits), is the destructor of this object guaranteed to be 
 called? I expect it to be so, as otherwise destructors seem pretty 
 useless (and dangerous), but cannot infer this from the spec.

When an object is collected by the GC, it's dtor will be called. However, the GC may not detect an orphaned object as collectable if there is a value in memory somewhere that "looks" like a reference to that object. Sean

There's also the problem with global objects: //------------------------------------------- import std.stdio; class A { ~this() { writefln("~A"); } } A tmp; void main() { tmp=new A; } //------------------------------------------- Nothing is printed.

Yes, this is my experience too. It also happens with objects stored in AA's I think. However, either of these fix the issue. void main() { auto tmp=new A; } . . . . void main() { auto tmp=new A; scope(exit) { delete tmp; } } -- Derek Parnell Melbourne, Australia "Down with mediocrity!"
Oct 16 2006
parent reply Carlos Santander <csantander619 gmail.com> writes:
Derek Parnell escribió:
 On Mon, 16 Oct 2006 15:34:22 -0500, Carlos Santander wrote:
 
 There's also the problem with global objects:

 //-------------------------------------------
 import std.stdio;

 class A
 {
      ~this()
      {
          writefln("~A");
      }
 }

 A tmp;

 void main()
 {
      tmp=new A;
 }
 //-------------------------------------------

 Nothing is printed.

Yes, this is my experience too. It also happens with objects stored in AA's I think. However, either of these fix the issue. void main() { auto tmp=new A; } . . . . void main() { auto tmp=new A; scope(exit) { delete tmp; } }

Of course, but sometimes "tmp" has to be global, so it's not good all the time. -- Carlos Santander Bernal
Oct 16 2006
parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Mon, 16 Oct 2006 20:08:30 -0500, Carlos Santander wrote:

 Derek Parnell escribió:
 On Mon, 16 Oct 2006 15:34:22 -0500, Carlos Santander wrote:
 
 There's also the problem with global objects:

 //-------------------------------------------
 import std.stdio;

 class A
 {
      ~this()
      {
          writefln("~A");
      }
 }

 A tmp;

 void main()
 {
      tmp=new A;
 }
 //-------------------------------------------

 Nothing is printed.

Yes, this is my experience too. It also happens with objects stored in AA's I think. However, either of these fix the issue. void main() { auto tmp=new A; } . . . . void main() { auto tmp=new A; scope(exit) { delete tmp; } }

Of course, but sometimes "tmp" has to be global, so it's not good all the time.

What do you mean? Doesn't "global" mean that the variable needs to be accessible until main() (or any module dtor for the 'main' module) exits? Thus this is also okay ... static ~this() { delete tmp; } -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 17/10/2006 11:32:08 AM
Oct 16 2006
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Derek Parnell" <derek nomail.afraid.org> wrote in message 
news:1iii9n8i8lu91.pvgnflxb8mfc$.dlg 40tude.net...

 What do you mean? Doesn't "global" mean that the variable needs to be
 accessible until main() (or any module dtor for the 'main' module) exits?

If "A tmp" is declared at global scope, writing "auto tmp = new A" in main() will not initialize it. It makes a local variable named "tmp" whose type is automatically deduced. Unless that's not what you were getting at at all..
 Thus this is also okay ...

  static ~this() { delete tmp; }

Yes, that works well. That's basically what I do to free any and all globally held resources (or those which are static members of classes, which are held in the same data segment I guess).
Oct 16 2006