2013-05-16 21 views
14

多くのメンバ変数を持つクラスに対して退屈な移動コンストラクタを書くことがよくあります。デフォルトの移動コンストラクタへの委任

A(A && rhs) : 
    a(std::move(rhs.a)), 
    b(std::move(rhs.b)), 
    c(std::move(rhs.c)), 
    d(std::move(rhs.d)) { 
    some_extra_work(); 
} 

彼らはいくつかの平凡な余分な作業をpeform、その後、デフォルトの移動のコンストラクタに関連付けられたすべてのアクションを実行し、次のとおりです。彼らは、次のようなものを見て。理想的には、デフォルトのムーブコンストラクタに委譲して余分な作業を実行しますが、自分自身のムーブコンストラクタを定義するとデフォルトの実装が定義されなくなり、デリゲートすることはありません。

このアンチパターンを回避する良い方法はありますか?

+6

困難を実装するために使用私のtidy_ptrタイプ、? 1つはすべてのデフォルトのコンストラクタを持ち、もう1つは 'some_extra_work'を行います。 *ゼロのルール*をチェックしてください。 – zch

+0

これが当てはまるかどうかは分かりませんが、 'A(A && rhs、int):A(rhs){}'はうまくいかないでしょうか? – Damon

+3

デフォルトの移動コンストラクタを持つ中間基本クラスが役に立ちます。 –

答えて

3

更新:この回答の最初の部分は無視して、より良い解決策がある最後にスキップしてください。

新しいタイプに余分な作業をラップし、それを継承:

class A; 

struct EW 
{ 
    EW(EW&&); 
}; 

class A : private EW 
{ 
    friend class EW; 
public: 
    A(A&&) = default; 
}; 

EW::EW(EW&&) { A* self = static_cast<A*>(this); self->some_extra_work(); } 

(あなたはまた、代わりに、基本クラスのデータメンバでそれを行うことができますが、あなたはoffsetofを使用して、いくつかのハックを必要とするだろう非標準レイアウト型では定義されていません)。継承を使用すると、変換にstatic_castを使用できます。

some_extra_work()が持っている場合、これは動作しませんが、基本クラスが最初に初期化されているので、メンバーが初期化され後 を行うことにします。

また、余分な作業が実際に移動元のオブジェクトで実行されている場合は、移動したときに自動的に動作するタイプのメンバーをラップする必要があります。私は、このような抽象的なレベルで言うのは、おそらくあなたは二つのクラスに `A`を分離し、別のものに1を入れることができRule of Zero

class A 
{ 
    tidy_ptr<D> d; 
public: 
    A() = default; 
    A(const A&) = default; 
    A(A&& r) = default; // Postcondition: r.d == nullptr 
}; 
+0

私は、基本クラスの移動元が*メンバーの移動前に呼び出されていないのだろうか? – Xeo

+0

それは余分な仕事が他のメンバーに頼っているならはいです。 「私にとっては、some_extra_work()の古典的な例は 'rhs.d = 0;' " –

+0

..."というOPのコメントを読んでいないと書いていたが、答えの2番目の部分は、 –