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

コードに明示的なインスタンス化はありません。

インスタンス化された静的データ メンバーの初期化の順序は、他の静的データ メンバー間ではありません。aしたがって、コードには実質的に未定義の動作があります。コンパイラが最初にマップを初期化するか、マップへの参照が有効かどうかによって異なります。

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

そのコードにはいくつかのエラーがあります。まず、最初のアイデアが良くありません。と の 2 つのグローバルな静的オブジェクトがaありA::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 answer を参照してください。

于 2015-06-25T20:44:19.930 に答える