C++ template static member instantiation
#include <map>
#include <iostream>
template <typename T>
class A
{
static std::map<int, int> data;
public:
A()
{
std::cout << data.size() << std::endl;
data[3] = 4;
}
};
template <typename T>
std::map<int, int> A<T>::data;
//std::map<int, int> A<char>::data;
A<char> a;
int main()
{
return 开发者_StackOverflow0;
}
What is wrong with this? Without explicit instantiation it breaks at
data[3] = 4;Explicit instantiation solves the problem but the program breaks after
std::cout << data.size() << std::endl;what means that the static class template memeber
data
was instantiated.There is no explicit instantiation in your code.
There is no order of initialization of instantiated static data members among other static data members. So your code has effectively undefined behavior: Depending on whether the compiler first initializes the map or a
, the reference to the map is valid or not.
See C++ Static member initialization.
I don't have Visual C++ handy, but I can see the same problem with your code compiling with GCC. You need the initialize the data member:
template<> std::map<int, int> A<char>::data = std::map<int, int>();
With this change, it compiles and runs correctly (for me on GCC on Linux).
There're several errors in that code. First the initial idea is not good. You have two global static objects: a
and A::data
. The order in which they're initialized is undefined. Depending on the mood of your compiler you have a 50% chance to have constructor of a
called first and attempted to write something into non-initialized A::data
.
This is sometimes called static init order fiasco problem. A suggested solution is to turn such objects into local static objects by moving them into functions:
#include <map>
#include <iostream>
template <typename T>
class A
{
std::map<int, int> &data()
{
static std::map<int, int> d;
return d;
}
public:
A()
{
std::cout << data().size() << std::endl;
data()[3] = 4;
}
};
int main()
{
A<char> a;
return 0;
}
Local static objects are initialized on first call to the function.
About the commented out "explicit instantiation" you forgot template <>
.
But after you prefix that line with template <>
it's still not definition but a declaration. It declares that there's A::data definition somewhere else. To actually define it you need to initialize it with something, see Jack Lloyd answer for example.
精彩评论