15

次のクラスを検討してください。

class A
{
public:
   std::string field_a;
   std::string field_b;
}

ここで、次のコピーの作成を検討してください。

A a1(a2);

A明示的なコピー コンストラクターがなくても、コピーの構築は適切にコピーされます。これは、コピー コンストラクターstd::stringがコンパイラによって生成された暗黙的なコピー コンストラクターによって呼び出されるためです。

私が知りたいのは、ムーブ コンストラクションについても同じことが言えますか?

編集:ここでのテストは次のことを示しています:

A a2(std::move(a1));

特定のムーブコンストラクターが次の場合を除き、実際にはコピー構築になります。

A( A && other ) : a(std::move(other.a)) {}

定義されています。

EDIT EDIT 私は Stephan T Lavavej に ping を打って、なぜ VC 2012 が暗黙のムーブ コンストラクター生成に関するドラフト 12.8 の状態に従っていないように見えるのかを尋ねました。彼は親切にも次のように説明してくれました。

バグというより「まだ実装されていない機能」です。VC は現在、私が右辺値参照 v2.0 と呼んでいるものを実装しています。ここでは、移動 ctors/assigns が暗黙的に生成されることはなく、copy ctors/assigns の暗黙的な生成に影響を与えることもありません。C++11 は右辺値参照 v3.0 を指定します。これは、あなたが見ているルールです。

4

2 に答える 2

16

はい、C++11 ドラフト 12.8 から:

クラス X の定義でムーブ コンストラクターが明示的に宣言されていない場合、1 つが暗黙的にデフォルトとして宣言されます。

  • X にはユーザー宣言のコピー コンストラクターがありません。
  • X には、ユーザー宣言のコピー代入演算子がありません。
  • X には、ユーザー宣言の移動代入演算子がありません。
  • X にはユーザー宣言のデストラクタがなく、
  • 移動コンストラクターは、暗黙的に削除済みとして定義されません。

最後の条件は、後で詳細に指定します。

暗黙的に宣言されたコピー/移動コンストラクターは、そのクラスのインライン パブリック メンバーです。クラス X のデフォルトのコピー/移動コンストラクターは、X が次の場合に削除済み (8.4.3) として定義されます。

  • 自明でない対応するコンストラクターを持ち、X が共用体のようなクラスであるバリアント メンバー、
  • オーバーロード解決 (13.3) が M の対応するコンストラクターに適用されるため、コピー/移動できないクラス型 M (またはその配列) の非静的データ メンバー。コンストラクタ、
  • オーバーロードの解決 (13.3) が B の対応するコンストラクターに適用されるため、コピー/移動できない直接または仮想基本クラス B
  • デストラクタが削除されているか、デフォルトのコンストラクタからアクセスできない型の直接または仮想基本クラスまたは非静的データ メンバー。
  • コピー コンストラクターの場合、右辺値参照型の非静的データ メンバー、または
  • 移動コンストラクターの場合、非静的データ メンバー、または移動コンストラクターを持たず、自明にコピーできない型を持つ直接または仮想基本クラス。

簡単に言えば、move コンストラクターは次の場合に暗黙的に宣言されます。

  1. このクラスには、ユーザーが宣言した他の特別なメンバー関数はありません。
  2. move コンストラクターは、すべてのメンバーとベースを移動することで適切に実装できます。

あなたのクラスは明らかにこれらの条件に準拠しています。

于 2012-11-12T14:34:15.733 に答える
6

コンパイラは、可能な場合、およびユーザー定義のコピー コンストラクターがない場合、移動コンストラクターを合成します。コピー コンストラクターがある場合にムーブ コンストラクターが合成されないという制限は、既存のコードを壊さないようにするためのものです。もちろん、すべてのメンバーが可動する必要があります。正確なルールはもう少し複雑です。

于 2012-11-12T14:01:20.103 に答える