static initialisation order issue with static/dynamic linking

Viewed 71

If a c++ application is organised in following manner

//file1.cpp
static Y sgObj = X::getInitObject(0);  //declared in file scope

//file2.cpp
namespace{
   int getInitValue()
   {
      static int val = Y::sObj.initVal();
      return val;
   }
}

namespace X{
   Y getInitObject(int initVal)
   {
      if(initVal < getInitValue())
      {
         cout << "Print some log message" << endl;
      } 

      return Y::initMethod(initVal);
   }
}

//file.h
//This class is shipped as static and dynamic library, and application is supposed to link 
//them in their executable based on their need
class Y{
public:
int initVal();
static Y initMethod(int val);
static Y sObj;
};

Assuming all the necessary header files are included and we are able to create the executable for this application, does it have initialization issue with the way I am creating the object in file1.cpp when:

  • statically vs
  • dynamically linking with the library(corresponding to implementation of class Y) for creating the object sgObj.

Given the class Y's implementation is not exposed to application, we can't change the way its static member sObj is created.

Does it have anything to do with platform / compiler being used?

1 Answers

You must either assure that file1.cpp includes <iostream> before the definition of sgObj or you need to construct a local object of type std::ios_base::Init before you use cout during the static initialization:

  if(initVal < getInitValue())
  {
     (void)std::ios_base::Init{};
     cout << "Print some log message" << endl;
  }

Otherwise cout might not be initialized when you reach that line.


Other than that, the order in which Y::sObj and the global sgObj are constructed is indeterminate, assuming Y::sObj is defined in another translation unit not shown, because the order in which dynamic initialization between different translation units happens is indeterminate.

Therefore, if Y::initMethod, which is called from the global initialization of sgObj accesses Y::sObj it might not be initialized yet, causing undefined behavior.

If you want to be able to use the static Y::sObj during static initialization of other non-local static variables, you need to use something like the Meyers singleton pattern:

class Y{
//...
    static Y& sObj {
        static Y instance /* initializer here */;
        return instance;
    }
};

To be used as Y::sObj() instead of Y::sObj.

Related