コピーコンストラクタ
クラス T
のコピーコンストラクタは、第1引数が T&、 const T&、 volatile T& または const volatile T& であって、他の引数がないか残りの引数すべてがデフォルト値を持つ、非テンプレートコンストラクタです。
目次 |
[編集] 構文
class_name ( const class_name & )
|
(1) | ||||||||
class_name ( const class_name & ) = default;
|
(2) | ||||||||
class_name ( const class_name & ) = delete;
|
(3) | ||||||||
ただし class_name は現在のクラス (またはクラステンプレートの現在の実体化) を表さなければなりません。 または、名前空間スコープまたはフレンド宣言で宣言されたときは、修飾されたクラス名でなければなりません。
[編集] 説明
- コピーコンストラクタの一般的な宣言。
- コピーコンストラクタを強制的にコンパイラに生成させます。
- コピーコンストラクタの暗黙の生成を回避します。
コピーコンストラクタは、オブジェクトが同じ型の別のオブジェクトから (直接初期化またはコピー初期化によって) 初期化されるときに呼ばれます (オーバーロード解決がより良いマッチを選択した場合または呼び出しが省略された場合は除きます)。 これには以下が含まれます。
- 初期化。 T a = b; または T a(b);、ただし b は
T
型です。 - 関数の引数渡し。 f(a);、ただし
a
はT
型でf
は void f(T t) です。 - 関数の戻り。 T f() のような関数の内部における return a;、ただし
a
はT
型であり、T
がムーブコンストラクタを持たない。
[編集] 暗黙に宣言されたコピーコンストラクタ
クラス型 (struct、 class または union) に対してユーザ定義されたコピーコンストラクタが提供されない場合、コンパイラは常にコピーコンストラクタをそのクラスの非 explicit かつ inline public
なメンバとして宣言します。 この暗黙に宣言されたコピーコンストラクタは、以下のすべてが真の場合、 T::T(const T&) の形式を持ちます。
-
T
の直接および仮想の基底B
のそれぞれが const B& または const volatile B& を引数とするコピーコンストラクタを持つ。 - クラス型またはクラスの配列型の
T
の非静的データメンバM
のそれぞれが const M& または const volatile M& を引数とするコピーコンストラクタを持つ。
そうでなければ、暗黙に宣言されたコピーコンストラクタは T::T(T&) です (これらのルールにより、暗黙に宣言されたコピーコンストラクタは volatile な左辺値引数を束縛できません)。
クラスは複数のコピーコンストラクタ、例えば T::T(const T&) と T::T(T&) の両方を持つことができます。 何らかのユーザ定義コピーコンストラクタが存在する場合でも、ユーザはキーワード |
(C++11以上) |
暗黙に宣言された (または最初の宣言においてデフォルト化された) コピーコンストラクタは、動的例外指定 (C++17未満)例外指定 (C++17以上)で説明されている通りの例外指定持ちます。
[編集] 削除された暗黙に宣言されたコピーコンストラクタ
以下の条件のいずれかが真の場合、クラス T に対する暗黙に宣言されたコピーコンストラクタは、未定義です。
|
(C++11未満) |
以下の条件のいずれかが真の場合、クラス T に対する暗黙に宣言されたまたはデフォルト化されたコピーコンストラクタは、削除されたものとして定義されます。
|
(C++11以上) |
-
T
がコピーできない (削除された、アクセス不可能な、または曖昧なコピーコンストラクタを持つ) 非静的データメンバを持つ。 -
T
がコピーできない (削除された、アクセス不可能な、または曖昧なコピーコンストラクタを持つ) 直接または仮想の基底クラスを持つ。 -
T
が削除されたまたはアクセス不可能なデストラクタを持つ直接または仮想の基底クラスを持つ。
|
(C++11以上) |
[編集] トリビアルなコピーコンストラクタ
以下の条件がすべて真の場合、クラス T
に対するコピーコンストラクタはトリビアルです。
- ユーザ定義されていない (つまり、暗黙に定義またはデフォルト化されている)。 また、デフォルト化されている場合は、そのシグネチャが暗黙に定義された場合と同じである)。 (C++14未満)
-
T
が仮想メンバ関数を持たない。 -
T
が仮想基底クラスを持たない。 -
T
のすべての直接の基底について、選択されたコピーコンストラクタがトリビアルである。 -
T
のすべてのクラス型 (またはクラスの配列型) の非静的メンバについて、選択されたコピーコンストラクタがトリビアルである。
非 union クラスに対するトリビアルなコピーコンストラクタは、実質的に引数のすべてのスカラーな部分オブジェクト (およびその部分オブジェクトの部分オブジェクトの…を再帰的に含みます) をコピーし、それ以外の処理を行いません。 しかし、パディングバイトはコピーされる必要はなく、値が同じである限り、コピーされた部分オブジェクトのオブジェクト表現が同じである必要さえもありません。
TriviallyCopyable なオブジェクトは、そのオブジェクト表現を手動で (例えば std::memmove で) コピーすることによってコピーできます。 C 言語と互換性のあるすべてのデータ型 (POD 型) はトリビアルにコピー可能です。
[編集] 暗黙に定義されたコピーコンストラクタ
暗黙に宣言されたコピーコンストラクタが削除されない場合は、 ODR 使用された場合、コンパイラによって定義されます (つまり、関数の本体が生成され、コンパイルされます)。 union 型の場合、暗黙に定義されたコピーコンストラクタは (std::memmove によって行われたかのように) そのオブジェクト表現をコピーします。 非 union クラス型 (class および struct) の場合、暗黙に定義されたコピーコンストラクタはそのオブジェクトの基底と非静的メンバの完全なメンバ単位のコピーを、その初期化の順序で、直接初期化を用いて行います。 これが constexpr コンストラクタの要件を満たす場合、生成されるコピーコンストラクタは constexpr
です。 (C++11以上)
|
(C++11以上) |
[編集] ノート
多くの状況で、たとえ可視な副作用を持つ場合でも、コピーコンストラクタは最適化によって除去されます。 コピー省略を参照してください。
[編集] 例
struct A { int n; A(int n = 1) : n(n) { } A(const A& a) : n(a.n) { } // ユーザ定義のコピコン }; struct B : A { // 暗黙のデフォコン B::B() // 暗黙のコピコン B::B(const B&) }; struct C : B { C() : B() { } private: C(const C&); // コピー禁止 (C++98 スタイル) }; int main() { A a1(7); A a2(a1); // コピコンを呼びます B b; B b2 = b; A a3 = b; // A& への変換 + コピコン volatile A va(10); // A a4 = va; // コンパイルエラー C c; // C c2 = c; // コンパイルエラー }
[編集] 欠陥報告
以下の動作変更欠陥報告は以前に発行された C++ 標準に遡って適用されました。
DR | 適用先 | 発行時の動作 | 正しい動作 |
---|---|---|---|
CWG 2171 | C++14 | X(X&) = default was non-trivial | made trivial |
CWG 496 | C++11 | structs with volatile members were trivially copyable | volatile members make copy non-trivial |
CWG 2094 | C++14 | volatile members make copy non-trivial | structs with volatile members are trivially copyable |