问题
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