Tadzys
Tadzys

Reputation: 1092

Global static variable initialised with a call to static class function in c++

Not sure how correctly formulate the question but here is the problem.

I have a static lib where I have the following class in a.h:

#pragma once
#include <vector>
class A{
public:
 void Run() {
  data_.push_back(10);
  std::cout << "size: " << data_.size() << std::endl;
 }
private:
 static std::vector<int> data_;
};

a.cpp is as follows:

#include "a.h"
std::vector<int> A::data_;

And I have another class in b.h:

#pragma once
#include <string>
class B
{
  public:
    static std::string Get();
};

And b.cpp:

#include "b.h"
#include "a.h"
std::string B::Get()
{
  static A a;
  a.Run();
  return "foo";
}

Now my main app which is using the above static lib is as follows:

#include <iostream>
#include "a.h"
#include "b.h"

static std::string var1= B::Get();

int main(int argc, char** argv)
{
  A a;
  a.Run();
}

Trying to understand why the output is:

size: 1

size: 1

There should be a single instance of each static data member for the entire class, so there should be a single call to A::data_ constructor. Am I hitting "static initialization order fiasco"? I.e. data_ is not initialised before I use it, but then I should be getting the crash?

And now lets imagine my data_ holds dynamically initialised items (something none POD). How will it be destructed if at the end data_ holds one item, although I've inserted 2?

And that's what actually is happening in my real life code (it sometimes crashes during destruction of data_).

Getting rid of global static ( static std::string var1= B::Get(); ) solves the problem, but I still want to understand the under the hood problem.

The described case can be reproduced in VS2015 (the real life case is reproducible in gcc 6.2 )

Upvotes: 0

Views: 94

Answers (1)

R Sahu
R Sahu

Reputation: 206577

Am I hitting "static initialization order fiasco"?

Most likely.

You can remove the problem by making the static data of a class available via a function call. E.g.

class A{
public:
 void Run() {
  getData().push_back(10);
  std::cout << "size: " << getData().size() << std::endl;
 }
private:
 static std::vector<int>& getData();
};

std::vector<int>& A::getData()
{
   static std::vector<int> data;
   return data;
}

When you do that, data will be initialized when A::getData() is called the first time. It removes the static initialization order issue completely.

Upvotes: 1

Related Questions