26


次のクラスを考慮して、moveコンストラクターを実装する正しい方法は何でしょうか。

class C {
public:
    C();
    C(C&& c);
private:
    std::string string;
}

もちろん、アイデアはstringそれを2回コピーまたは割り当て解除することを避けることです。
基本的な例はわかりやすくするためのものであり、moveコンストラクターが必要であると仮定しましょう。


私は試した:

C::C(C&& c) {
    //move ctor
    string = std::move(c.string);
}

C::C(C&& c) : string(std::move(c.string)) {
    //move ctor
}

どちらもgcc4.8で正常にコンパイルされ、正常に実行されます。オプションAは正しい動作であり、オプションstringBで移動する代わりにコピーされるようです。
これは、移動コンストラクターの正しい実装ですか?

4

4 に答える 4

15

それstd::string自体が move-ctor を持っているため、暗黙的に定義された move-ctor forCが適切な移動操作を処理します。自分で定義できない場合があります。ただし、他のデータメンバーがあり、具体的には:

12.8 クラスオブジェクトのコピーと移動

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

— 非自明な対応するコンストラクターを持つバリアント メンバーであり、X は共用体のようなクラスです。

— オーバーロードの解決 (13.3) が M の対応するコンストラクターに適用されるため、コピー/移動できないクラス型 M (またはその配列) の非静的データ メンバー。デフォルトのコンストラクタ、または

— オーバーロードの解決 (13.3) が B の対応するコンストラクターに適用されるため、コピー/移動できない直接または仮想基本クラス B

— 移動コンストラクターの場合、移動コンストラクターを持たず、自明にコピーできない型を持つ非静的データ メンバーまたは直接または仮想基本クラス。

13クラス X のコピー/移動コンストラクターは、それがユーザーによって提供されたり削除されたりしない場合、自明です。

— クラス X には、仮想関数 (10.3) も仮想基本クラス (10.1) も、関数 (10.3) も仮想基本クラス (10.1) もありません。

— 各直接基底クラス サブオブジェクトをコピー/移動するために選択されたコンストラクターは自明であり、

— クラス型 (またはその配列) である X の非静的データ メンバーごとに、そのメンバーをコピー/移動するために選択されたコンストラクターは自明です。それ以外の場合、コピー/移動コンストラクターは自明ではありません。

独自の move-ctor を実装したい場合があります。

move-ctor が必要な場合は、イニシャライザ リスト構文を使用してください。いつも!そうしないと、イニシャライザ リストに記載されていないオブジェクトごとのデフォルトの構築になってしまう可能性があります (これは、デフォルト以外の ctor を持つメンバー オブジェクトに対してのみ強制されるものです)。

于 2012-05-01T18:27:59.810 に答える
11

両方のバリアントが文字列を移動します。後で割り当てを移動するためだけにデフォルトで空の文字列を構築しないため、2 番目のバリアントを優先する必要があります。

テストケースを確認してから、コンパイラの bugzilla リストを確認してください。string::operator=(string&&)(1 番目のケース) (2 番目のケース)の両方への呼び出しを追跡する必要があるstring::string(string&&)のは、両方のケースでそれらが移動することを確認する場合です。

于 2012-05-01T18:31:02.243 に答える
3

両方のコンストラクターが機能するはずです。したがって、どちらも正しい移動コンストラクターです。最初のデフォルトの構成stringは割り当てのみを行うため、2 番目の構成はより効率的である可能性があります。2 つ目の方法が効率的でない場合は、コンパイラのバグ (現在のコンパイラでは C++11 のサポートがまだ完全ではないことを思い出してください) またはテスト方法論の欠陥 (コピーと移動をどのように正確にテストし、移動コンストラクターを確実にテストしますか) が疑われます。どちらの場合も代入 op は呼び出されませんか?)。

もちろん、コンパイラにコンストラクタを生成させることができる場合はいつでもC(C&&) = default;.

于 2012-05-01T18:32:22.360 に答える
2

メモリを手動で管理する必要がないため、ここで移動コンストラクターを実装する必要はありません。移動コンストラクターは、クラスで動的配列を手動で使用する場合にのみ役立ちます。

要求しなくても、デフォルトのmoveコンストラクターが既に作成されているはずなのに、コンパイラーに明示的に作成させることができます。

C(C&& c) = default;
于 2012-05-01T18:24:56.683 に答える