C ++模板静态成员实例化

时间:2010-09-13 22:44:48

标签: c++ templates static instantiation member

#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 0;
}

这有什么问题?在没有显式实例化的情况下,它会在

 data[3] = 4; 
处中断。显式实例化解决了问题,但程序在
std::cout << data.size() << std::endl;
之后中断,这意味着静态类模板memeber data已被实例化。

< / p>

3 个答案:

答案 0 :(得分:4)

您的代码中没有明确的实例化。

在其他静态数据成员中没有实例化静态数据成员的初始化顺序。因此,您的代码具有有效的未定义行为:根据编译器是首先初始化地图还是a,对地图的引用是否有效。

请参阅C++ Static member initialization

答案 1 :(得分:2)

我没有方便的Visual C ++,但我可以看到使用GCC编译代码时遇到的问题。您需要初始化数据成员:

template<> std::map<int, int> A<char>::data = std::map<int, int>();

通过此更改,它可以正确编译和运行(对于我在Linux上的GCC上)。

答案 2 :(得分:1)

该代码中存在多个错误。首先,最初的想法并不好。您有两个全局静态对象:aA::data。初始化它们的顺序是不确定的。根据编译器的情绪,您有50%的机会首先调用a的构造函数,并尝试将某些内容写入未初始化的A::data

这有时会被称为static init order fiasco问题。建议的解决方案是将这些对象转换为本地静态对象:

#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;
}

首次调用函数时初始化本地静态对象。

关于注释掉的“显式实例化”,您忘记了template <>

但是,在使用template <>作为前缀后,它仍然不是定义,而是声明。它声明A :: data definition 在其他地方。要实际定义它,你需要用它来初始化它,例如,请参阅Jack Lloyd的回答。