Destructor nonsense on dlang.org

foobar foo at bar.com
Fri May 25 05:05:01 PDT 2012


On Friday, 25 May 2012 at 11:23:40 UTC, Jacob Carlborg wrote:
> On 2012-05-25 11:02, foobar wrote:
>
>> It makes the call order deterministic like in C++.
>>
>> e.g.
>> class Foo {}
>>
>> struct A {
>> resource r;
>> ~this() { release(r); }
>> }
>>
>> struct B {
>> A* a;
>> Foo foo;
>> ~this() { delete a; } // [1]
>> }
>
> I though we were talking about classes holding structs:
>
> class B {
>     A* a;
>     Foo foo;
>     ~this() { delete a; }
> }
>
> In this case you don't know when/if the destructor of B is 
> called. It doesn't help to wrap it in a struct, you could just 
> have put it directly in A. Is that correct?
>

No. see below.

>> Lets look at point [1]:
>> The "foo" instance is "managed" by the GC since the only 
>> resource it
>> holds is memory. The "a" member wraps some "non-managed" 
>> resource (e.g.
>> file descriptor) and in this model is still valid, thus allows 
>> me to
>> deterministically dispose of it as in c++.
>
> Ok, but if B is a class?
>
>> This can be simply checked at compile-time - you can only 
>> reference non
>> class instance members in the destructor, so adding a "delete 
>> foo;"
>> statement at point [1] simply won't compile.
>
> If you have a pointer to a struct you don't know how it was 
> created. It's possible it's been created with "new", which 
> means the garbage collector needs to delete it.

let's say we add two classes:
class FooA {
   A a;
}
class FooPA {
   A* pa;
}

For the first case, both the class and the struct share the same 
lifetime thus when an instance of FooA is GC-ed, the GC would 
call A's d-tor and allow it to do what-ever (self) cleaning it 
requires. This means the d-tor will always be called.

For the second case, The GC will only scan "pa" to find inner 
class instances but will *not* handle the struct value itself.
In order to clean what "pa" points to, you need to explicitly 
call the destructor yourself. One way to do this would be to 
register a callback with the GC to get notified when an instance 
of FooPA is collected and inside the callback function maintain a 
reference-counter.
This also means that if you allocate a struct value on the heap 
via "new" you are responsible to call delete _yourself_ and the 
gc will not call it for you.
I think that loosing this small convenience is worth it - we gay 
more orthogonal semantics that are easier to reason about.




More information about the Digitalmars-d mailing list