C++11 のルールでは、6 つの要素 (デフォルト コンストラクター、コピー コンストラクター、移動コンストラクター、コピー割り当て、移動割り当て、およびデストラクタ) がデフォルトで生成されます。2 番目のルールでは、カスタム コピー、移動、またはデストラクタが定義されている場合、それらのデフォルト操作は生成されません。ただし、次のコードではそうではありません。ただし、このコードはエラーでコンパイルに失敗します。
call to implicitly deleted copy constructor of 'Uni'
Uni 用の独自のコピー コンストラクターを作成すると、すべて正常に動作します。(コード内にコメントが付けられており、参照用に提供されています)
ご意見をいただければ幸いです。
最後に、私はこれを Mac、LLVM コンパイラー付きの Xcode で実行しています。
どうもありがとう...
#include <iostream>
class A
{
public:
A(int i) :num{i}
{
std::clog<< "ctor A() num = " << num << "\n";
}
A( A const &aRef)
:num{aRef.num}
{
std::clog << " copy ctor A( A const &aRef) num = " << num << "\n";
}
int value()
{
return num;
}
private:
int num;
};
class Uni
{
public:
Uni(A* aptr) : up{aptr}
{
std::clog << " ctor Uni value = " << up.get()->value() << "\n";
}
/*Uni(Uni const &uRef)
{
std::clog << " copy ctor Uni copying obj pointed by unique_ptr\n";
up.reset(uRef.up.get() ? new A{*uRef.up.get()} : nullptr);
}*/
private:
std::unique_ptr<A> up;
};
int main(int argc, const char * argv[])
{
Uni one{new A{10}};
Uni two{one}; //default copy ctor is implicitly deleted. why ?
}
ベストアンサー1
特別なメンバーの自動生成に関する C++11 のルールは、あなたが投稿したほど単純ではありません。最も重要な違いは、場合によっては、メンバーが暗黙的に宣言されているが、削除済みとして定義されていることです。これがあなたのケースで起こっていることです。
C++11、[クラス.コピー]§11:
クラスのデフォルト化されたコピー/移動コンストラクタは、次
X
の場合に削除済みとして定義されます (8.4.3)X
。
- 対応するコンストラクタが非自明であり、
X
ユニオンのようなクラスであるバリアントメンバー、- の対応するコンストラクタに適用されたオーバーロード解決(13.3)の結果が曖昧さをもたらすか、またはデフォルト化されたコンストラクタから削除されるかアクセスできない関数となる
M
ため、コピー/移動できないクラス型(またはその配列)の非静的データメンバー、M
B
の対応するコンストラクタに適用されたオーバーロード解決(13.3)の結果が曖昧になるか、またはデフォルト化されたコンストラクタから削除されたりアクセスできない関数になるため、コピー/移動できない直接または仮想基底B
クラス、- デフォルトコンストラクタから削除されるかアクセスできないデストラクタを持つ型の直接または仮想基底クラスまたは非静的データメンバー。
- コピーコンストラクタの場合は、右辺値参照型の非静的データメンバー、または
- 移動コンストラクターの場合、非静的データ メンバー、または移動コンストラクターを持たず簡単にコピーできない型を持つ直接または仮想基本クラス。
(強調は筆者による)
より一般的には、自動生成されたクラス メンバーのルールは次のとおりです。
クラスにユーザー提供のコンストラクターがない場合、デフォルト コンストラクターが宣言されます。
クラスにユーザー提供のコピー コンストラクターがない場合、コピー コンストラクターが宣言されます。
クラスに { ユーザー提供のコピーまたは移動コンストラクター、ユーザー提供のコピーまたは移動代入演算子、ユーザー提供のデストラクタ } のいずれも含まれていない場合は、移動コンストラクターが宣言されます (ただし、以下の (*) を参照してください)。
クラスにユーザー提供のコピー代入演算子がない場合、それが宣言されます。
クラスに { ユーザー提供のコピーまたは移動コンストラクター、ユーザー提供のコピーまたは移動代入演算子、ユーザー提供のデストラクタ } のいずれも含まれていない場合は、移動代入演算子が宣言されます (ただし、以下の (*) を参照してください)。
クラスにユーザー提供のデストラクタがない場合、デストラクタが宣言されます。
自動的に宣言されたメンバーは、デフォルトとして定義 (デフォルトの処理を実行) することも、削除として定義 (使用しようとするとエラーが発生する) することもできます。経験則は、「デフォルト バージョンが意味をなす場合は、デフォルトとして定義されます。そうでない場合は、削除として定義されます。」です。
この文脈では、「意味がある」とは、「削除された関数、あいまいな関数、アクセスできない関数、またはその他の不正な関数を呼び出そうとしない」ことを意味します。たとえば、この回答の最初の部分で引用した標準ビットには、コピー コンストラクターにとって「意味がない」ものがリストされています。
さらに、クラスにユーザー提供の移動コンストラクターまたは移動代入演算子がある場合、自動的に宣言されたコピー コンストラクターまたはコピー代入演算子は削除済みとして定義されます。
(*) 自動的に宣言された移動コンストラクターまたは移動代入演算子が削除済みとして定義される場合、代わりにまったく宣言されません。このルールは、そのようなクラスを移動しようとすると、エラーを生成する代わりに暗黙的にコピーにフォールバックするように存在します。