0

I'm getting strange behavior from c++ constructors and need clarification please. Recently, I wanted to make use of the Singleton pattern. After searching online for examples and modifying the code to meet my need, I ran into an unexpected behavior. Simply the consturctors are called before main() starts. To save you time going over the code, which is 4 classes. I simply have, main.cpp, First.cpp, Second.cpp, Third.cpp and Singleton.cpp.

In main.cpp

int main()
{
    cout << "Inside main()" << endl;
    cout<<"val = "<<Singleton::Instance()->callThem()<<endl;
    delete Singleton::Instance();
    return 0;
}

The sequence of calls is: main() -> Singleton::callThem() -> First::callFirst() -> Second::callSecond() -> Third::callThird()

Singleton.cpp

#include "singleton.h"
#include <iostream>

First first; //source of the problem

Singleton::Singleton()
{
    std::cout<<"Singleton Constructor"<<std::endl;
}

Singleton::~Singleton()
{
    std::cout<<"Singleton Destructor"<<std::endl;
}

Singleton* Singleton::m_pInstance = NULL;

Singleton* Singleton::Instance()
{
    if (!m_pInstance)
    {
        m_pInstance = new Singleton;
    }
    return m_pInstance;
}

    int Singleton::callThem()
{
    return first.callFirst();
}

The output as follows:

Third Constructor
Second Constructor
First Constructor
Inside main()
Third Constructor
Second Constructor
First Constructor
Singleton Constructor
val = 3
Singleton Destructor
First Destructor
Second Destructor
Third Constructor
First Destructor
Second Destructor
Third Constructor

How can constructors be called before Inside main()? Isn't main() where execution begins?

If I remove First first; //source of the problem, the first line that prints out is Inside main(), no constructors called before main(). Would appreciate your clarification.

Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
WhatIf
  • 653
  • 2
  • 8
  • 18
  • Possible duplicate of [C++: When (and how) are C++ Global Static Constructors Called?](http://stackoverflow.com/questions/1271248/c-when-and-how-are-c-global-static-constructors-called) – Ami Tavory Mar 05 '16 at 18:43
  • It has been my experience the the sequence of global ctors can not be controlled, and can change from one build to the next, and this can seriously impact your testing ... how do you confirm that you have tested the sequence delivered to your customers? One team I worked with simply disallowed this challenge. – 2785528 Mar 05 '16 at 19:07

3 Answers3

1

No, global objects are constructed before main [or at least, before your code in main executes - there are compilers that insert a call to "initialize global objects" before the first code provided by the programmer, but these days, most compilers do this by having a "pre-main" function that gets built by the compiler/linker].

Note also that the order between different translation units' global constructors is completely undefined - the order is defined within a particular translation unit in the order they are declared.

This is a true nuisance, but it's also a terribly hard problem to solve in a better way. Best solution is to construct objects as and when you need them, rather than use globals - even if that's can be a bit tricky too.

It is possible that making the Singleton return a shared_ptr can solve the problem - I have used something like that to keep a lock alive, where each place that uses the lock has a copy of the shared pointer, and thus only when the last user of the lock is gone does the lock itself get deleted. This five-line change went with a 30-line comment explaining why this was necessary, and an almost as long commit message, because this is tricky stuff that can be easily broken by someone thinking "ah, but we can remove some of this stuff". [Not saying shared_ptr is tricky, but using shared_ptr instead of a single global variable IS]

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
0

Globals are constructed and initialized before main() is run.

If you're looking for a singleton pattern, I'd recommend just using:

template <typename T>
class Singleton {
  public:
     static T *GetInstance() {
          static T value;
          return &value;
     };
};

int main() {
    int *x = Singleton<int>::GetInstance();
}
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
0

Would appreciate your clarification.

A simple to understand approach to control the initializaton (ctor) sequence of objects you think you might want to have globally accessed might be ...

a. replace any global instance of 'class T' from

T1 theT1;  // a global instance, with no control of initialization sequence

to

T1* theT1 = nullptr; // a global instance ptr, constructed when you want.

Repeat for each global object.

b. explicitly initialize the handle after main(), probably early in main() but certainly before the object is needed.


Note that there is much literature on the techniques to create a singleton in the face of multiple threads. The book version of singleton is not thread safe. (I think the authors have one sentence that says none of the patterns in the pattern book are thread safe.)

Taking explicit control of the ctor sequence adds immensely to the confidence that you tested what you shipped.

2785528
  • 5,438
  • 2
  • 18
  • 20