2

名前空間の一部の const オブジェクトを初期化する際に問題が発生しています。次のような名前空間があります。

namespace myNamespace{
    const std::string HI = "Hi";
    const std::string BYE = "Bye";

    inline std::vector<std::string> createHiAndByeVector(){
        std::vector<std::string> temp;
        temp.push_back(HI);
        temp.push_back(BYE);
        return temp;
    }

    const std::vector<std::string> HI_AND_BYE = createHiAndByeVector();
}

HI初期化をデバッグするとBYE、文字列リテラルが割り当てられていることがわかります。実行は initialziae まで続きHI_AND_BYEますが、関数に入ると、 と のcreateHiAndByeVector()両方HIBYE値がなくなります。次に、push_back()メソッドでセグメンテーション違反が発生します。コール スタックを見ると、次の行が表示されます__static_initialization_and_destruction_0()。何が起こっている?オブジェクトが構築された直後に破棄されますか?

4

2 に答える 2

1

私の推測では、ここでの問題は、One Definition Rule (ODR) の違反です。ここでの推測は、このコードが実際にはヘッダーにあるということです。これが、関数をインラインとして宣言した理由でもあります。

現在、このコードは複数の翻訳単位 (.cpp ファイル)、TU1 および TU2 でコンパイルされています。これにより、定数とインライン関数の両方が 2 セットになります。これで、リンク時に、内部リンケージがあるため、定数は互いに独立して存在します (名前空間レベルの const はこれを引き起こします)。ただし、この関数には内部リンケージがなく、リンカはinline. 現在、残りの 1 つは TU1 と TU2 の両方でベクトルを初期化するために使用されていますが、そのうちの 1 つの定数文字列を使用しています。これらがいつ初期化されるか (未定義) に応じて、機能する場合と機能しない場合があります。これは基本的に、上記の Deamonpog が言及した初期化順序の大失敗です。

ODR に戻ると、問題はインライン関数が 2 回コンパイルされることですが、異なる文字列定数を暗黙的に参照するため、それらは同じではありません。ヘッダーに匿名の名前空間がある場合、同様の問題が発生します。ところで: それ以外は、この問題は名前空間とは何の関係もありません! これを解決するには、次の 2 つの方法があります。

  1. init 関数も静的にします。これにより、これらすべての定数と関数が他の翻訳単位の兄弟から分離されます。
  2. ヘッダーで定数を宣言 ( )し、別の TU でextern string const BYE;実装( ) するだけです。string const BYE = "Bye!";そうすれば、プログラムのさまざまな部分で共有できるインスタンスが 1 つだけになります。
于 2013-02-17T10:41:46.540 に答える
-1

これは初期化フィアスコによるものだと思います。次のリンクが役立つ場合があります。問題は、グローバル/静的変数がランダムに初期化されることです。それらを初期化する特定の順序はありません。したがって、HIまたはBYEが初期化される前に、HI_AND_BYEが初期化される可能性があります。!!!

C++の静的初期化順序の問題を見つける

http://www.parashift.com/c++-faq-lite/static-init-order.html

于 2013-02-17T02:07:37.420 に答える