auto classes and finalizers

Bruno Medeiros brunodomedeirosATgmail at SPAM.com
Fri Apr 14 08:44:28 PDT 2006


pragma wrote:
> In article <e1m6mo$19d$1 at digitaldaemon.com>, Bruno Medeiros says...
>> *** The extended GC algorithm: ***
>>
>> delete:
>>
>>   m = getMemManagerHandle(obj);
>>   if(m.isDeleted)
>>     return;
>>   if(m.isObjectInstance)
>>     m.obj.destroy(); // calls ~this()
>>   if(!m.isGarbageSet) // If it is not in S
>>     freeMemory(m);
>>
>> GC:
>>
>>   GC determines a set S of instances to be reclaimed (garbage);
>>   foreach(m in S) {
>>     m.isGarbage = true;
>>   }
>>   foreach(m in S) {
>>     delete m;
>>   }
>>   foreach(m in S) {
>>     freeMemory(m);
>>   }
> 
> Something like this will help *part* of the problem.  By delaying the freeing of
> referenced memory, dynamically allocated primitives (like arrays) will continue
> to function inside of class destructors.  However, this does not help with
> references to objects and structs, as they may still be placed in an invalid
> state by their own destructors.
> 
> /**/ class A{
> /**/   public uint resource;
> /**/   public this(){ resource = 42; }
> /**/   public ~this(){ resource = 0; }
> /**/ }
> /**/ class B{
> /**/   public A a;
> /**/   public this(){ a = new A(); }
> /**/   public ~this(){ writefln("resource: %d",a.resource); }
> /**/ }
> 
> Depending on the ording in S, the program will output either "resource: 42" or
> "resource: 0".  The problem only gets worse for object cycles.  I'm not saying
> it won't work, but it just moves the wrinkle into a different area to be stomped
> out.
> 

True, I forgot to mention that. The order of destruction is undefined, 
so it will only work with objects where that order doesn't matter. (that 
should be the case with most)

> Now, one way to improve this is if there were a standard method on objects that
> can be checked in situations like these.  That way you'd know if another object
> is finalized, or in the process of being finalized.
> 
>>   foreach(m in S) {
>>     m.isFinalized = true;
>>     delete m;
>>   }
> 
> Now this doesn't make life any easier, but it does make things deterministic.
> 
> /**/ class A{
> /**/   public uint resource;
> /**/   public this(){ resource = 42; }
> /**/   public ~this(){ resource = 0; }
> /**/ }
> /**/ class B{
> /**/   public A a;
> /**/   public this(){ a = new A(); }
> /**/   public ~this(){ if(!a.isFinalized) writefln("resource: %d",a.resource); }
> /**/ }
> 
> (another option would be something like gc.isFinalized(a), should the footprint
> of Object be an issue)
> 
> Now B outputs nothing if A is finalized.  That seems like a win, but what if B
> really needed that value before A went away?  In such a case, you're back to
> square-one: you can't depend on the state of another referenced object within a
> dtor, valid reference or otherwise.
> 
> - EricAnderton at yahoo

Exactly, you can't really solve the order/state problem with this. I 
think the only way to do it is to manually memory manage the member 
objects (with a construct such as mmnew or otherwise).

-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D



More information about the Digitalmars-d mailing list