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

这有什么问题?如果没有明确的实例化,它会在

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

4

3 回答 3

4

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

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

请参阅C++ 静态成员初始化

于 2010-09-16T10:15:26.680 回答
2

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

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

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

于 2010-09-14T16:56:12.953 回答
1

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

这有时被称为静态初始化命令惨败问题。一个建议的解决方案是通过将这些对象移动到函数中来将它们变成本地静态对象:

#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 定义。要实际定义它,您需要使用某些东西对其进行初始化,例如,请参阅 Jack Lloyd 的答案。

于 2015-06-25T20:44:19.930 回答