0

So I'm reading that for Zero Initialization will initialize:

Every named variable with static or thread-local storage duration that is not subject to constant initialization, before any other initialization

I am using a Singleton with the traditional private constructor and a static public method in which there is a local static singleton object which the method will be return.

My problem is that the class also has a static vector which is zero-initialized and it seems to be getting initialized after the singleton, meaning that I cannot interact with it. Is there something that governs this initialization order or is that simply implementation defined?


This is a simplification of what my code looks like:

class Foo {
    Foo(){ s_vec.push_back(13); }
public:
    static Foo& Get() {
        static Foo singleton;
        return singleton;
    }

    int Front() const { return s_vec.front(); }
    static vector<int> s_vec;
};
vector<int> Foo::s_vec;

I'm running into this problem because elsewhere in the code I'm initializing a static global variable like this and not getting 13: static const auto element = Foo.Get().Front()

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 3
    Is there a need to make the vector static if the intent is to only have the one instance? – Phil M Dec 20 '18 at 20:59
  • 1
    Note: "error: cannot call member function ‘Foo& Foo::Get()’ without object." I think you meant for this function to be static. – 2785528 Dec 21 '18 at 03:51
  • 1
    How did you determine " it seems to be getting initialized after the singleton "? My trivial test suggests the Foo::s_vec exists before Foo::Get() is invoked. – 2785528 Dec 21 '18 at 04:01
  • 1
    "Foo& Get()" should be "static Foo& Get()", I assume? – Philipp Claßen Dec 21 '18 at 04:03

1 Answers1

0

Constructor for global variables are executed before the start of main, but the order across compilation units is not specified.

The Foo constructor in your example should only be called once you call Foo::Get. If the first time you call it is in main, the static vector will be already initialized.

One situation, where you can run into the race that you describe is when you call Foo::Get in the initialization code of another global object, especially when the code is in another compilation unit.

But in a simple test like this here, the vector should always be initialized first and there will be no possible race:

class Foo {
    Foo() = default;
public:
    static Foo& Get() {
        static Foo singleton;
        return singleton;
    }
    static vector<int> s_vec;
};
vector<int> Foo::s_vec; // will be initialized before main

int main() {
  Foo::Get(); // --> triggers constructor call Foo::Foo
  return 0;
}

(I'm assuming Foo::Get is a static member in the singleton, otherwise you cannot instantiate it. But it does not make a difference conceptually.)

The problematic scenario could look like this:

// other file
struct Bar {
  Bar() { Foo::Get(); }
};
Bar bar; // global object

You have no control about the initialization order of Foo::s_vec (in the first compilation unit) and bar (in the second one).

Philipp Claßen
  • 41,306
  • 31
  • 146
  • 239
  • I'm finally back from Christmas break! I've tried to clarify my question. I realized that my example did not clearly illustrate my problem: "The class also has a static vector which is zero-initialized and it seems to be getting initialized after the singleton, meaning that I cannot interact with it." – Jonathan Mee Jan 02 '19 at 13:37