www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - What on earth is happening? Mutual dtors

reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
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. 
Aug 20 2005
parent reply xs0 <xs0 xs0.com> writes:
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. 
 
 

Aug 21 2005
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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.
Aug 21 2005
parent Bruno Medeiros <daiphoenixNO SPAMlycos.com> writes:
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. 
 

undefined and incorrect behaviour (same as calling free() twice on a malloc'ed block). -- Bruno Medeiros Computer Science/Engineering student
Aug 25 2005