web-dev-qa-db-ja.com

メンバー初期化子リストをインクリメントすると、未定義の動作が発生しますか?

これは未定義の動作を引き起こしていますか?具体的には、初期化子リストの増分とそれがどのように評価されるか。

class Wrinkle {
public:
    Wrinkle(int i) : a(++i), b(++i), x(++i) {}
private:
    int a;
    int x;
    int b;
};

メンバーの宣言と初期化子リストの順序の違いは、これがまさにその違いを示す例であるため意図されているため、今のところ無視してください。

24
TwoOfDiamonds

これは未定義の振る舞いを生成しません。

[class.base.init]#7

[注:各mem-initializerによって実行される初期化は、完全な式を構成します。 mem-initializer内のすべての式は、初期化を実行する完全な式の一部として評価されます。 ]

[intro.execution]

5。 完全な式は

  • [...]
  • 初期化子の構成式を含む、init-declaratorまたはmem-initializer、

9。 完全式に関連するすべての値の計算と副作用は、評価される次の完全な式に関連するすべての値の計算と副作用の前にシーケンスされます。


ただし、次の点に注意してください。

[class.base.init]#1

非委任コンストラクターでは、初期化は次の順序で進行します。

  • [...]

  • 次に、非静的データメンバーは、クラス定義で宣言された順序で初期化されます(ここでも、mem-initializersの順序に関係なく)。

したがって、コードはi + 1aに、i + 2xに、i + 3bに効果的に割り当てます。

31
Holt

C++ 17標準には例が含まれています 質問とほぼ同じです

struct B1 { B1(int); /* ... */ };
struct B2 { B2(int); /* ... */ };
struct D : B1, B2 {
  D(int);
  B1 b;
  const int c;
};

D::D(int a) : B2(a+1), B1(a+2), c(a+3), b(a+4) { /* ... */ }
D d(10);

これに注意が続きます:

[注:各mem-initializerによって実行される初期化は、完全な式(4.6)を構成します。 mem-initializer内の式はすべて、初期化を実行する完全な式の一部として評価されます。 —エンドノート]

リンクをたどると、セクション4.6は、 「完全な式」の定義は の1つであることを示しています。

...初期化子の構成式を含むmem-initializer、

「イニシエーラの構成式を含む」というフレーズは、次のイニシャライザに進む前に++iの副作用が完了するため、上記のコードが合法であることを強く示唆しています。これは私の標準の読み方ですが、私よりも標準的な経験を持っている人なら誰にでも任せることができてうれしいです。

(メンバーの初期化は、メンバー初期化リストに表示される順序ではなく、クラスで宣言された順序で行われることにも注意してください)。

6
Tristan Brindle