Thread overview
destructors and GC again
Oct 16, 2006
Lutger
Oct 16, 2006
Derek Parnell
Oct 16, 2006
Lutger
Oct 16, 2006
Sean Kelly
Oct 16, 2006
Lutger
Oct 16, 2006
Carlos Santander
Oct 16, 2006
Derek Parnell
Oct 17, 2006
Carlos Santander
Oct 17, 2006
Derek Parnell
October 16, 2006
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'.

October 16, 2006
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!"
October 16, 2006
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?
October 16, 2006
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
October 16, 2006
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."
October 16, 2006
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
October 16, 2006
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!"
October 17, 2006
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
October 17, 2006
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
October 17, 2006
"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).