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?

JJacobsson
  • 153
  • 7
  • Compiled with: g++ (GCC) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21) on Linux 2.6.18-5-amd64 #1 SMP x86_64 GNU/Linux – JJacobsson May 08 '09 at 09:04

2 Answers2

6

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
  • 13,797
  • 1
  • 42
  • 71
  • There are two instances of A, the static one and the one in main. – James Hopkin May 08 '09 at 09:14
  • It's the static from GetAInstance() –  May 08 '09 at 09:15
  • 1
    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 May 08 '09 at 13:22
  • @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 Feb 01 '10 at 15:13
  • @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 Feb 01 '10 at 16:44
0

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.

Ricardo Amores
  • 4,597
  • 1
  • 31
  • 45