tags:

views:

202

answers:

2
// edited by Neil Butterworth to conserve vertical space
#include <stdio.h>

struct A;
struct B;

A& GetAInstance();
B& GetBInstance();

struct A {  
    A() {
        printf( "A\n" );
    }
    ~A() {
        printf( "~A\n" );
        B& b = GetBInstance();
    }
};

struct B {
    B() {
        printf( "B\n" );
    }

    ~B() {
        printf( "~B\n" );
        A& a = GetAInstance();
    }
}; 

A& GetAInstance() {
    static A a;
    return a;
}

B& GetBInstance() {
    static B b;
    return b;
}

int main( ) {
    A a;
}

Consider the above scenario. I would expect this to result in an infinite reference loop resulting in the program being unable to exit from static de-initialization, but the program ran just fine with the following printout:

  A
  ~A
  B
  ~B
  A
  ~A

Which was unexpected.

How does a compiler deal with this situation? What algorithms does it use to resolve the infinite recursion? Or have I misunderstood something fundamental? Is this, somewhere in the standard, defined as undefined?

+4  A: 

The compiler effectively stores a bool with each static to remember whether it has been initialised.

This is the order:

Inside main:

  • Construct A
  • Destruct A
    • Construct static B

Clean-up of statics:

  • Destruct static B
    • Construct static A
    • Destruct static A

3.6.3/1 in the Standard specifies it should work this way, even when a static is constructed during clean-up as in this case.

James Hopkin
Just wondering why there is a second A.
Daniel Brückner
There are two instances of A, the static one and the one in main.
James Hopkin
It's the static from GetAInstance()
anon
Of course! Thanks! Overlooked the one in main().
Daniel Brückner
Important Note: Is that the reference of B returned when destroying the static A is now a reference to an invalid or destroyed instance.
Martin York
@Martin Actually it's a reference to an object that is being destroyed. Its lifetime has ended, so there are restrictions on what you can do with it, but there's no undefined behaviour.
James Hopkin
@James: Never said there was (in the above code). There would be undefined behavior __if__ the destructor of A tried to use the reference of the static B to do anything (Which was the point I was trying to make above).
Martin York
A: 

That behaviour is probably caused because you are using static instances. The compiler surely takes care of the status of static variables to avoid performing multiple initialization / deinitializations.

Ricky AH