標準によると、
クラスXの定義が移動コンストラクターを明示的に宣言していない場合は、次の場合に限り、暗黙的にデフォルトとして宣言されます。
— Xにはユーザー宣言のコピーコンストラクターがありません。
— Xには、ユーザーが宣言したコピー代入演算子はありません。
— Xには、ユーザー宣言の移動代入演算子がありません。
— Xには、ユーザーが宣言したデストラクタはありません。
今、以下はコンパイルに失敗します
# include <utility>
class Foo
{
public:
Foo() = default;
Foo(Foo const &) = delete;
};
int main()
{
Foo f;
Foo g(std::move(f)); // compilation fails here
return 0;
}
したがって、削除された関数はユーザー定義と見なされるようです。これは理にかなっています(デフォルトの実装ではありません)。しかし、その特定のケースでは、どのようにして削除されたコピーコンストラクタ/割り当ての混乱がデフォルトの移動コンストラクタ/割り当てを削除するでしょうか?
この問題は、手動で生成するため、実用的に重要だと思います。このようなデフォルト関数のメンテナンスはエラーが発生しやすいと同時に、クラスメンバーがコピー不可能なクラスを以前よりもはるかに一般的な獣にしたので、std::unique_ptr
などのクラスの使用の(正しい)増加です。
user-declared
は、user-provided(defineddefined by the user)、explicitly defaulted(= default
)またはexplicitly deleted(= delete
)とは対照的に、暗黙的にデフォルト/削除された(などあなたの移動コンストラクタとして)。
したがって、あなたのケースでは、yes移動コンストラクタがimplicitly削除されるため、コピーコンストラクターは明示的に削除されます(したがってuser-declared)。
ただし、その特定のケースでは、コピーコンストラクター/割り当ての混乱したデフォルトの移動コンストラクター/割り当てをどのように削除しますか?
そうではありませんが、標準はこのケースと複雑なケースを区別しません。
最も短い答えは、implicitly定義されたmove-constructorにexplicitly削除されたcopy-constructormight場合によっては危険です。user-definedデストラクタがあり、userがない場合も同様です。 -definedcopy-constructor( のルール/ 5 /ゼロ を参照)。これで、ユーザー定義のデストラクタがコピーコンストラクタを削除しないと主張できますが、これは単に言語の欠陥であり、多くの問題が発生するため削除できません。古い(悪い)プログラムの。 Bjarne Stroustrupを引用するには:
理想的な世界では、デフォルトとして「世代なし」を決定し、「通常の操作をすべて提供してください」という非常に単純な表記を提供すると思います。 [...]また、「デフォルトの操作なし」ポリシーはコンパイル時のエラー(簡単な修正方法があるはずです)につながりますが、デフォルトの生成ポリシーは実行時まで検出できない問題を引き起こします。
この詳細については N3174 = 10-0164 を参照してください。
ほとんどの人は /5 /ゼロのルール に従うことに注意してください。私の意見では、そうすべきです。デフォルトのmove-constructorを暗黙的に削除することにより、標準は間違いからユーザーを「保護」し、場合によってはcopy-constructorを削除することで以前から保護していたはずです(Bjarneの論文を参照)。
興味があればさらに読む:
この問題は、手動で生成するため、実用的に重要だと思います。このようなデフォルト関数のメンテナンスはエラーが発生しやすいと同時に、クラスメンバーがコピー不可能なクラスを以前よりもはるかに一般的な獣にしたので、
std::unique_ptr
などのクラスの使用の(正しい)増加です。
Moveコンストラクタを明示的にデフォルトに設定すると、この問題が解決します。
class Foo {
public:
Foo() = default;
Foo(Foo const &) = delete;
Foo(Foo&&) = default;
};
デフォルトの移動コンストラクターでコピー不可能なオブジェクトを取得します。私の意見では、これらの明示的な宣言は暗黙的な宣言よりも優れています(たとえば、コピーコンストラクターを削除せずに、移動コンストラクターをdefault
として宣言するだけです)。
あなたが述べたように、§12.8から
クラスXの定義が移動コンストラクターを明示的に宣言していない場合は、次の場合に限り、暗黙的にデフォルトとして宣言されます。
Xにはser-declaredコピーコンストラクターがありません。
[...]
user-declaredに注意してください。しかし、§8.4.3を見ると:
次の形式の関数定義:
属性指定子シーケンスopt decl-specifier-seqopt 宣言子virt-specifier-seqopt =削除;
削除済みdefinitionと呼ばれます。 definitionが削除された関数は、削除された関数とも呼ばれます。
declare it以外で、削除された関数を暗黙的または明示的に参照するプログラムは、形式が正しくありません。
したがって、標準ではdelete
d関数をser-declaredとして定義しています(上記からわかるように)。ただし、これらはdelete
dであり、使用できません。
次に、§12.8によると、ユーザー宣言(= delete;
付き)コピーコンストラクターがあるため、暗黙のmoveコンストラクターは定義されません。