1

クラス C に静的 unordered_map があります。関数 main を含むファイルとは別のファイルにクラス定義と宣言を配置すると、動作に違いが生じます。

問題は、クラス C が関数 main と同じコンパイル単位にある場合、すべて問題なく、「新しい文字列が作成されました: c」というテキストが 1 回だけ表示されることです。ただし、コードを 3 つのファイルに分割すると (以下のリストを参照)、「新しい文字列が作成されました: c」が 2 回表示されます。これは、静的な unordered_map が main に入る直前に消去されることを意味します。

私の質問は次のとおりです。なぜこれが起こるのですか?(違いは、Apple LLVM コンパイラ 4.1 でコンパイルした場合にのみ発生します。 g++4.7 -std=c++11 でテストしたところ、分割コードは問題なく動作しました。)
アイデアをお寄せいただきありがとうございます。

// 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");
}
4

2 に答える 2

6

グローバル オブジェクトの初期化の順序は、1 つの翻訳単位内でのみ定義されます。異なる翻訳間の順序は保証されません。したがって、std::unordered_map構築される前にアクセスされた結果の動作が見られる可能性があります。

もちろん、これらの問題を回避する方法は、グローバル オブジェクトを使用しないことです。グローバルオブジェクトを本当に使用する必要がある場合は、オブジェクトを関数でラップするのが最善です。このようにして、オブジェクトが最初にアクセスされたときに構築されることが保証されます。C++ 2011 では、構築はさらにスレッドセーフです。

T& global() {
    static T rc;
    return rc;
}
于 2012-12-15T15:20:26.770 に答える
0

みんなありがとう!ディートマーのアドバイスに従って、私はこれを行いました:

class C{
//...
private:
  static unordered_map<string, string*>& m();
};

unordered_map<string, string*>& C::m()
{
  static unordered_map<string, string*> m;
  return m;
}

そして、私は参照し続けましたm()。それが以前に起こらなかったのは奇妙です。運が良かったと思います。しかし、これは警告メッセージのケースであるはずですよね?


このような間違いを避けるために、次のマクロを使用して静的変数を宣言および定義します。

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

この場合の使用法:

class C{
//...
private:
  DECLARE_STATIC(unordered_map<string, string*>, m);
}
DEFINE_STATIC(unordered_map<string, string*>, m)
于 2012-12-15T15:31:05.847 に答える