Thread overview
What on earth is happening? Mutual dtors
Aug 21, 2005
xs0
Aug 25, 2005
Bruno Medeiros
August 21, 2005
Out of curiosity, I wrote this:

import std.stdio;

class A
{
 B b;
 ~this()
 {
  delete b;
  writefln("a dtor: ",cast(void*)b);
 }
}

class B
{
 A a;
 ~this()
 {
  delete a;
  writefln("b dtor: ",cast(void*)a);
 }
}

void main()
{
 A a=new A;
 B b=new B;
 a.b=b;
 b.a=a;

 delete a;

 fflush(stdout);
}

I expected it to get caught in an infinite loop between the two dtors, but surprisingly, all that is printed is

a dtor: 0
b dtor: 0

But then, the program hangs in gc_term().

What is happening here?  Why don't the objects get caught in an infinite loop between their dtors?  And if they're no longer pointing to one another after they are dtor'ed (but most likely not GCed), why does gc_term() hang?

On a side note, this code does not hang the gc_term():

import std.stdio;

class A
{
 B b;
 bit isDeleting;
 ~this()
 {
  isDeleting=1;
  if(!b.isDeleting)
   delete b;
 }
}

class B
{
 A a;
 bit isDeleting;
 ~this()
 {
  isDeleting=1;
  if(!a.isDeleting)
   delete a;
 }
}

void main()
{
 A a=new A;
 B b=new B;
 a.b=b;
 b.a=a;

 delete a;
}

Which is odd.  For some reason, mutually calling dtors doesn't cause the dtors to stick in an infinite loop, but it causes gc_term() to.  But even though the classes have the same structure in this example, and their pointers to one another have the same values (null), gc_term() doesn't hang.


August 21, 2005
Hi,

"delete a;" will also set a to null, so you can't delete it twice, hence no loop..

I'm not sure about gc_term, though, but I think it's first a bug that you try to delete a twice (once from main, once from b)...


xs0

Jarrett Billingsley wrote:
> Out of curiosity, I wrote this:
> 
> import std.stdio;
> 
> class A
> {
>  B b;
>  ~this()
>  {
>   delete b;
>   writefln("a dtor: ",cast(void*)b);
>  }
> }
> 
> class B
> {
>  A a;
>  ~this()
>  {
>   delete a;
>   writefln("b dtor: ",cast(void*)a);
>  }
> }
> 
> void main()
> {
>  A a=new A;
>  B b=new B;
>  a.b=b;
>  b.a=a;
> 
>  delete a;
> 
>  fflush(stdout);
> }
> 
> I expected it to get caught in an infinite loop between the two dtors, but surprisingly, all that is printed is
> 
> a dtor: 0
> b dtor: 0
> 
> But then, the program hangs in gc_term().
> 
> What is happening here?  Why don't the objects get caught in an infinite loop between their dtors?  And if they're no longer pointing to one another after they are dtor'ed (but most likely not GCed), why does gc_term() hang?
> 
> On a side note, this code does not hang the gc_term():
> 
> import std.stdio;
> 
> class A
> {
>  B b;
>  bit isDeleting;
>  ~this()
>  {
>   isDeleting=1;
>   if(!b.isDeleting)
>    delete b;
>  }
> }
> 
> class B
> {
>  A a;
>  bit isDeleting;
>  ~this()
>  {
>   isDeleting=1;
>   if(!a.isDeleting)
>    delete a;
>  }
> }
> 
> void main()
> {
>  A a=new A;
>  B b=new B;
>  a.b=b;
>  b.a=a;
> 
>  delete a;
> }
> 
> Which is odd.  For some reason, mutually calling dtors doesn't cause the dtors to stick in an infinite loop, but it causes gc_term() to.  But even though the classes have the same structure in this example, and their pointers to one another have the same values (null), gc_term() doesn't hang. 
> 
> 
August 21, 2005
"xs0" <xs0@xs0.com> wrote in message news:de9c60$2tpq$1@digitaldaemon.com...
> Hi,
>
> "delete a;" will also set a to null, so you can't delete it twice, hence no loop..
>
> I'm not sure about gc_term, though, but I think it's first a bug that you try to delete a twice (once from main, once from b)...

But "delete a" in main() will not set the 'a' member of 'B' to null; only the reference to 'a' in main() gets nullified.  Meaning that you can call delete twice on 'a', although the second time, it has already been deleted and is still sitting in memory, not yet GCed.

In fact, here's another example that causes gc_term() to hang.

import std.stdio;

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

void main()
{
 A a=new A;
 A a2=a;

 delete a;

 writefln("a: ",cast(void*)a);
 writefln("a2: ",cast(void*)a2);

 delete a2;

 writefln("a2: ",cast(void*)a2);

 fflush(stdout);
}


It seems that calling delete on an object twice (though it should really never happen) makes gc_term() hang.  I don't know why.


August 25, 2005
Jarrett Billingsley wrote:
 >
> It seems that calling delete on an object twice (though it should really never happen) makes gc_term() hang.  I don't know why. 
> 
I suppose calling delete twice on the same object is illegal and causes undefined and incorrect behaviour (same as calling free() twice on a malloc'ed block).

-- 
Bruno Medeiros
Computer Science/Engineering student