3

こんにちは、いくつかの値を持つ静的な std::map と、このようなデフォルト要素への静的イテレータがあり、両方を一度に初期化します。

.h ファイル内

class foo
{
    static std::map<std::string, int> sqlenumToInt;
    static std::map<std::string, int> initEnumToInt();
    static std::map<std::string, int>::iterator defaultIt;
};

.c ファイルで

std::map<std::string, int> foo::sqlenumToInt = initEnumToInt();

std::map<std::string, int> foo::defaultIt = std::map<std::string, int>::iterator();

std::map<std::string, int> foo::initEnumToInt();
{
    std::map<std::string, int> test;
    defaultIt = test.insert(std::make_pair("a", 0)).first
    test["b"] = 2;
    test["c"] = 3;
    test["d"] = 4;
    return test;
}

静的変数の初期化のデフォルトの順序。sqlenumToInt の最初の要素への std::map::iterator() または iterator のみが defaultIt になりますか??

4

6 に答える 6

3

翻訳単位内では、静的変数の初期化順序が明確に定義されています。static 変数は定義順に初期化されます。したがって、初期化される前にinitEnumToInt実行されます。コードでは、これにより未定義の動作が発生します。これは、実行時に初期化されていない (ただしゼロ初期化された) 状態であるためです。次に、ゼロで初期化されたオブジェクトを呼び出し、後でゼロまたは初期化されていないオブジェクトを期待するコンストラクターを呼び出しています。 foo::defaultItinitEnumToIntfoo::defaultItoperator=

于 2012-09-06T12:02:44.323 に答える
2

あなたが書いた方法では、初期化子sqlenumToIntが最初に評価されるため、初期化されていない要素にアクセスしています。これは未定義の動作である可能性があります (反復子の型の詳細によって異なります)。

マップの前面が必要な場合はdefaultIt = sqlenumToInt.begin()、イニシャライザで言って、から削除しinitEnumToInt()ます。

(さらに、関数で取得した反復子も、ローカル マップ オブジェクトが破棄されるとすぐに無効になるため、意味がありません。)

于 2012-09-06T11:58:51.513 に答える
1

ファイル スコープ変数は、定義順に初期化されます。サンプル コードでsqlenumToIntは、 が最初に初期化され、 が呼び出されます。これは、関数呼び出しの最後で無効になるイテレータ値にinitEnumToInt設定されます (これは を指し、破棄され、 のコピーを取得します)。次に、明示的な初期化が開始され、デフォルトで構築された反復子が格納されます。defaultIttestsqlenumToInttestdefaultIt

于 2012-09-06T12:00:03.400 に答える
0
std::map<std::string, int>::iterator();

この行は のデフォルトイテレータを構築するためmap<string, int>defaultItこのデフォルト イテレータの単なるコピーになります。最初のマップ要素が必要な場合は、 で初期化する必要がありますsqlenumToInt.begin()

初期化の順序に関しては、1 つのコンパイル単位内で、静的変数は定義した順序で初期化されますが、異なる単位間の順序は定義されていません。

于 2012-09-06T12:01:44.740 に答える
0

内部のこの行にinitEnumToInt()は問題があります:

defaultIt = test.insert(std::make_pair("a", 0)).first

このコードには 2 つの問題があります。1 つ目は、イテレータが行に到達する前に構築されていないため、イテレータに自明なコンストラクタ (初期化されていないオブジェクトの呼び出し) がない場合operator=、未定義の動作が発生することです。これは場合によっては問題ではありませんが、コード移植できません)。

その行の 2 番目の問題は、ローカルマップ内の要素を参照するように反復子を設定していることです。関数の完了後にその反復子を使用すると、未定義の動作になります。

関数内でイテレータを設定しても、コードにはまったく値が追加されないことに注意してください。したがって、セッターは脇に置いておくことができます。その要素を参照するイテレータが必要な場合は、複数のことができます。それが常に最初のsqlenumToInt.begin()要素である場合は、マップ内の特定の要素を参照する場合は、イニシャライザに設定します(関数sqlenumToInt.find(element)内でのみ認識される特定の要素に設定する場合は、initEnumToIntイテレータが最初に初期化されるように初期化の順序を変更し、それをinitEnumToInt参照による引数として機能します。--これは必須ではありません。パブリックな静的変数であるため、関数はとにかくアクセスできますが、参照によって渡すと依存関係が生じ、コード内で明示的に関数内で変更されるという事実が生じます。

于 2012-09-06T12:27:13.503 に答える