static unordered_map is erased when putting into different compilation unit in XCode

こ雲淡風輕ζ 提交于 2019-12-20 03:53:06

问题


I have a static unordered_map in my class C. I experience difference in behaviour if I put my class definition and declaration in different files from the file containing function main.

The thing is that I observed that if the class C is in the same compilation unit as function main, all is well, I see only once the text "new string created: c". However if I split my code into three files (see the listing below), I see "new string created: c" twice which means that my static unordered_map is wiped right before entering main.

My question would be: why does this happen? (The difference only happens when compiling with Apple LLVM compiler 4.1. I have tested it with g++4.7 -std=c++11 and the split code works out just fine.)
Thanks in advance for any ideas!

// would go to My_header.h

#include <unordered_map>
#include <string>
#include <iostream>

using namespace std;    

class C{
public:
  C(const string & s);
private:
  static unordered_map<string, string*> m;
  string *name;
};

// would go to My_code.cpp    
// (when separated, add #include "My_header.h")

unordered_map<string, string*> C::m;

C::C(const string & s):
name(NULL)
{
  string*& rs = m[s];
  if(rs)
  {
    name = rs;
  }
  else
  {
    cout<<"new string created: "<<s<<endl;
    rs = name = new string(s);
  }
}

// would go to main.cpp
// (when separated, add #include "My_header.h")

C c("c");

int main(int argc, const char * argv[])
{
  cout << "main" << endl;
  C c1("c");
}

回答1:


The order of initialization of global objects is defined only within one translation unit. Between different translation the order isn't guaranteed. Thus, you probably see behavior resulting from the std::unordered_map being accessed before it is constructed.

The way to avoid these problems is to not use global objects, of course. If you realky need to use a global object it is best to wrap the object by a function. This way it is guaranteed that the object is constructed the first time it is accessed. With C++ 2011 the construction is even thread-safe:

T& global() {
    static T rc;
    return rc;
}



回答2:


Thanks, guys! Following Dietmar's advice, I did this:

class C{
//...
private:
  static unordered_map<string, string*>& m();
};

unordered_map<string, string*>& C::m()
{
  static unordered_map<string, string*> m;
  return m;
}

and then I kept referring to m(). It is strange that it did not happen before. I guess I got lucky. But then, this should be a case for a warning message, shouldn't it?


To avoid mistakes like this I will use the following macros to declare and define static variables:

/// Use this macro in classes to declare static variables
#define DECLARE_STATIC(type, name) static type& name();

/// Use this macro in definition files to define static variables
#define DEFINE_STATIC(type, name) type& name(){static type local; return local;}

Usage in this case:

class C{
//...
private:
  DECLARE_STATIC(unordered_map<string, string*>, m);
}
DEFINE_STATIC(unordered_map<string, string*>, m)


来源:https://stackoverflow.com/questions/13893349/static-unordered-map-is-erased-when-putting-into-different-compilation-unit-in-x

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!