0

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 )

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

8 Comments

@R Sahu, yes, indeed your suggestion gets rid of the problem. Although there is one more important detail: if in destructor of a class you need to call any static function, make sure to do the same call in costructor, otherwise it might be already destructed.
@Tadzys, I don't recall construction and destruction of static objects inside functions being a problem at all, If you run into any issues, please start another post with the relevant details.
@R Sahu, lets say my getData holds static std::vector<int*>
@Tadzys, that points to poor design. It's not a good idea to store pointers in static objects. You can come up with convoluted logic to deal with them but avoid them if you can. Use std::vector<std::vector<int>> instead.
@R Sahu, lets say getData holds static std::vector<int*> and in destructor I want to clean up the vector, but getData() was called prior to constructor (constructor might not be called at all), so you will get either a leak or a crash. My specific solution was to call getData() in constructor (this way I will guarantee that destructor will be called prior to vector destructor). Of course using smart pointers helps to avoid the problem as well.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.