2016-02-04 5 views
5

C++ 11では、暗黙的な生成が自動的に防止されている場合、特別なメンバー関数を明示的にデフォルトすることができます。明示的にデフォルトの特別なメンバー関数の生成を実施する

しかし、特別なメンバ関数を明示的にデフォルトにすると、他の特別なメンバ関数(コピー操作、デストラクタなど)のいくつかを手動で宣言することによる暗黙の削除のみが元に戻ります。機能が実際には生成できない場合でも、コードは適切に形成されているとみなされます。

次のシナリオを検討してください:

struct A 
{ 
    A()   = default; 
    A (const A&) = default; 
    A (A&&)  = delete; // Move constructor is deleted here 
}; 

struct B 
{ 
    B()   = default; 
    B (const B&) = default; 
    B (B&&)  = default; // Move constructor is defaulted here 

    A a; 
}; 

そうすることは、コンパイル・エラー(Aの動きコンストラクタが削除された)を引き起こすため、Bに移動コンストラクタは、コンパイラによって生成されることはありません。 Aのコンストラクタを明示的に削除しなければ、Bの移動コンストラクタは期待通りに生成されます(移動するのではなく、Aをコピーします)。そのようなオブジェクトを移動しようとすると、

は黙っ代わりにコピーコンストラクタを使用します。

B b; 
B b2 (std::move(b)); // Will call B's copy constructor 

は、関数を生成するか、それができない場合は、コンパイル・エラーを発行するのいずれかにコンパイラを強制する方法はありますか?この保証がないと、削除された単一のコンストラクタがオブジェクト階層全体の移動を無効にできる場合、デフォルトの移動コンストラクタに依存することは困難です。

+0

あなたが含まれているメンバーが移動可能であるかどうかは分かりませんか? – NathanOliver

+2

クラスが最初に実装されたときにそれらは移動可能ですが、後でメンバーが追加されると、移動可能な要件が見落とされる可能性があります(特に、他のメンバーによって追加された場合)。 –

+1

移動コンストラクタを削除しますが、コピーコンストラクタを削除しないタイプは非常に奇妙です。これを行うことによって得られるべきことは全くありません。だからこそ、この事件を無視するのが最善の方法かもしれません。なぜなら、誰かが何の理由もなくばかげたことをした結果であると考えているからです。 –

答えて

3

Aのようなタイプを検出する方法があります。しかし、型が明示的にの場合、移動コンストラクタは削除されます。移動コンストラクタが暗黙的に削除されて生成された場合、オーバーロード解決には関与しません。このため、AでなくてもBは移動可能です。 Bdefault移動コンストラクタです。つまり、暗黙的に削除されてコピーが行われます。

Bは構成可能です。ただし、Aはありません。だから、この単純な問題です:

struct B 
{ 
    static_assert(is_move_constructible<A>::value, "Oops..."); 

    B()   = default; 
    B (const B&) = default; 
    B (B&&)  = default; // Move constructor is defaulted here 

    A a; 
}; 

さて、あなたが欲しいものを行うにはコピーのみのタイプが含まれている任意の型を引き起こす一切一般方法はありません。つまり、各タイプごとに静的にアサートする必要があります。 Bの移動が失敗するように、デフォルトの移動コンストラクターに構文を記述することはできません。

その理由は、下位互換性があるためです。ユーザ定義のコピーコンストラクタを宣言したすべてのC++ 11以前のコードについて考えてみてください。 C++ 11のムーブコンストラクタジェネレーションのルールによって、それらのすべてがムーブコンストラクタを削除していました。つまり、T t = FuncReturningTByValue();という形式のコードは、コピーコンストラクタを呼び出してC++ 98/03でうまく動作したにもかかわらず、失敗することになります。したがって、move-by-copyの問題は、移動コンストラクターを生成できなかった場合、移動する代わりにこれらのコピーを作成することで回避できました。

= defaultは「通常どおりにやること」を意味するため、暗黙的に削除された移動コンストラクタを無視するこの特別なオーバーロード解決動作も含まれています。

関連する問題