0
struct C{
    std::vector<int> foo;
    const int &bar;
    C();
};

C::C(): bar(foo[0]){
    foo.push_back(5);
}

コードはコンパイルできましたが、コンパイルされたファイルは実行できませんでした。

参照バーを初期化するこの方法の何が問題になっていますか? foo が bar の前に宣言されている限り、foo[0] を使用してコンストラクターで bar を初期化できると思いましたか?

なぜこれが当てはまるのか、誰かが何か考えを与えることができますか?

4

2 に答える 2

0

ベクターは空の状態です。初期化リストは、括弧内のコードの前にオブジェクトを構築するため、push_back影響しませんbar(foo[0])。したがってfoo[0]、空のベクトルにアクセスしていて、範囲外です。

vectorサイズ変更が発生するたびに、要素への参照が無効になることに注意してください。したがって、ベクトル要素への参照を保持する価値はありません。

于 2013-07-18T23:04:40.403 に答える
0

foo は初期化されていないため、初期化子リストを使用して、bar の前に少なくとも 1 のサイズで foo を初期化できます。これは c++98 でも有効です。

struct C{
    std::vector<int> foo;
    const int &bar;
    C();
};

C::C() : foo(1)  // initialize foo with size 1
       , bar(foo[0]) {
    foo[0]=5;    // this is guarateed to be exception safe
}

ただし、イニシャライザ リストの順序に注意する必要があります。構造体/クラスでの宣言の順序で並べられます。ここを参照

ISO/IEC 14882:2003(E) セクション 12.6.2 によると:

初期化は次の順序で進行します。

  • 最初に、以下で説明するように、最も派生したクラスのコンストラクターに対してのみ、仮想基底クラスは、基底クラスの有向非巡回グラフの深さ優先の左から右への走査に現れる順序で初期化されます。 -to-right」は、派生クラス base-specifier-list 内の基本クラス名の出現順序です。
  • 次に、直接基底クラスは、base-specifier-list に表示される宣言順に初期化されます (mem-initializer の順序に関係なく)。
  • 次に、非静的データ メンバーは、クラス定義で宣言された順序で初期化されます (これも mem-initializer の順序に関係なく)。
  • 最後に、コンストラクターの本体が実行されます。

編集:

Kerrek SBのコメントのおかげで、ベクターを使用できません。何かをプッシュしている間、foo はサイズ変更 (再割り当て) され、bar は正しい参照を失います。std::dequeベクトルを使用するか、決して渡されない特定のサイズに初期化することができます。

于 2013-07-18T23:12:27.923 に答える