简体   繁体   中英

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 ah:

#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 bh:

#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" ? Ie 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 )

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. Eg

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM