14

に関連するN2628によると、非静的データメンバー初期化子は、明示的に定義されたコンストラクターによってオーバーライドできますが、暗黙的に定義されたコピーコンストラクターについては少し曖昧に見えます。

特に、Apple clangバージョン3.0では、構造体(またはクラス)がPODであるかどうかによって動作が異なることに気付きました。

次のプログラムは出力「1」を返します。これは、コピーコンストラクターが右側を無視し、代わりに新しい非静的データメンバー初期化子(この例では、X :: aのブール真の値)を置き換えていることを示します。 )。

#include <iostream>
#include <string>

struct X
{
    std::string string1;
    bool a = true;
};

int main(int argc, char *argv[])
{
    X x;
    x.a = false;
    X y(x);
    std::cout << y.a << std::endl;
}

ただし、紛らわしいことに、string1をコメントアウトすると

    // std::string string1;  

その場合、動作は期待どおりに機能します(出力は「0」です)。おそらく、暗黙的に生成されたコピーコンストラクターがないため、データがコピーされます。

C ++ 0x仕様は、暗黙的に定義されたコピーコンストラクターが右側のコンテンツをコピーしないようにするのが良い考えであることを本当に示唆していますか?それはあまり役に立たず、直感的ではありませんか?非静的メンバー初期化機能は非常に便利だと思いますが、これが正しい動作である場合は、そのトリッキーで直感的でない動作のため、この機能を明示的に回避します。

私が間違っていると言ってください。

更新:このバグはClangソースリポジトリで修正されました。このリビジョンを参照してください。

更新:このバグは、Apple clangバージョン3.1(tags / Apple / clang-318.0.45)(LLVM 3.1svnに基づく)で修正されたようです。このバージョンのclangは、Xcode 4.3forLionの一部として配布されました。

4

1 に答える 1

10

結局のところ、それは影ではありません。標準の抜粋の強調表示された部分を参照してください。

デフォルトのコピー/移動コンストラクター(§12.8)のセクションは、全体を引用するには少し長すぎます。結論として、初期化子を含む非静的メンバーフィールドは、デフォルトのcopy/moveコンストラクターによって単純にコピーされます。

§12.8:

-6。非ユニオンクラスXの暗黙的に定義されたコピー/移動コンストラクターは、そのベースとメンバーのメンバーごとのコピー/移動を実行します。[ Note: brace-or-equal-initializers of non-static data members are ignored. See also the example in 12.6.2. —end note ]初期化の順序は、ユーザー定義コンストラクターのベースとメンバーの初期化の順序と同じです(12.6.2を参照)。xをコンストラクターのパラメーター、またはmoveコンストラクターの場合はパラメーターを参照するxvalueとします。各ベースまたは非静的データメンバーは、そのタイプに適した方法でコピー/移動されます。

  • メンバーが配列の場合、各要素は対応するxのサブオブジェクトで直接初期化されます。
  • メンバーmの右辺値参照型がT&&の場合、static_cast(xm)で直接初期化されます。
  • それ以外の場合、ベースまたはメンバーは、対応するxのベースまたはメンバーで直接初期化されます。
    仮想基本クラスのサブオブジェクトは、暗黙的に定義されたコピー/移動コンストラクターによって一度だけ初期化されます。

これは参照されるサンプルです:

struct A {
    int i = /* some integer expression with side effects */;
    A(int arg) : i(arg) { }
    // ...
};

A(int)コンストラクターは、iをargの値に初期化するだけであり、iのbrace-or-equalinitializerの副作用は発生しません。—end example ]


完全を期すために、デフォルトのデフォルトコンストラクターの対応するセクション:

§12.1

-6。デフォルトで削除済みとして定義されていないデフォルトのコンストラクターは、クラスタイプ(1.8)のオブジェクトを作成するためにodr-used (3.2)で使用される場合、または最初の宣言後に明示的にデフォルト設定される場合に暗黙的に定義されます。
暗黙的に定義されたデフォルトコンストラクターは、ctor-initializer(12.6.2)がなく、空の複合ステートメントを使用せずに、そのクラスのユーザー作成のデフォルトコンストラクターによって実行されるクラスの初期化のセットを実行します。そのユーザー作成のデフォルトコンストラクターの形式が正しくない場合、プログラムの形式は正しくありません。
そのユーザー作成のデフォルトコンストラクターがconstexprコンストラクター(7.1.5)の要件を満たす場合、暗黙的に定義されたデフォルトコンストラクターはconstexprです。クラスのデフォルトのデフォルトコンストラクターが暗黙的に定義される前に、その基本クラスとその非静的データメンバーのすべての非ユーザー提供のデフォルトコンストラクターが暗黙的に定義されている必要があります。[注:暗黙的に宣言されたデフォルトコンストラクターには、例外仕様(15.4)があります。
明示的にデフォルト設定された定義には、暗黙的な例外仕様がある場合があります。8.4を参照してください。—end note ]

于 2011-11-21T20:58:40.787 に答える