コピーコンストラクタ
コピーコンストラクタは、同じクラス型の引数を指定して呼び出すことができ、引数を変更せずにその内容をコピーするコンストラクタです。
目次 |
[編集] 構文
class-name (parameter-list ); |
(1) | ||||||||
class-name (parameter-list ) function-body |
(2) | ||||||||
class-name (single-parameter-list ) = default; |
(3) | (C++11以降) | |||||||
class-name (parameter-list ) = delete; |
(4) | (C++11以降) | |||||||
class-name ::class-name (parameter-list ) function-body |
(5) | ||||||||
class-name ::class-name (single-parameter-list ) = default; |
(6) | (C++11以降) | |||||||
| class-name | - | コピーコンストラクタが宣言されているクラス |
| parameter-list | - | 次の条件をすべて満たす空ではないパラメータリスト
|
| single-parameter-list | - | 型がT&、const T&、volatile T&、またはconst volatile T&であり、デフォルト引数を持たない1つのパラメータのみのパラメータリスト |
| 関数本体 | - | コピーコンストラクタの関数本体 |
[編集] 説明
struct X { X(X& other); // copy constructor // X(X other); // Error: incorrect parameter type }; union Y { Y(Y& other, int num = 1); // copy constructor with multiple parameters // Y(Y& other, int num); // Error: `num` has no default argument };
コピーコンストラクタは、オブジェクトが同じ型の別のオブジェクトから初期化されるとき(直接初期化またはコピー初期化によって。ただし、オーバーロード解決がより適切なマッチを選択するか、呼び出しが省略される場合を除く)に呼び出されます。これには以下が含まれます。
- 初期化: T a = b; または T a(b);、ここで b は型
Tです。 - 関数引数渡し: f(a);、ここで a は型
Tであり、 f は void f(T t) です。 - 関数からの戻り値: return a; (T f() のような関数内で、a が型
Tであり、ムーブコンストラクタを持たない場合)。
[編集] 暗黙的に宣言されるコピーコンストラクタ
ユーザー定義のコピーコンストラクタがクラス型に提供されていない場合、コンパイラは常に、そのクラスの非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&)の両方です。
|
いくつかのユーザー定義コピーコンストラクタが存在する場合でも、ユーザーはキーワードdefaultを使って暗黙のコピーコンストラクタ宣言を強制することができます。 |
(C++11以降) |
暗黙的に宣言された(または最初の宣言でデフォルト化された)コピーコンストラクタは、動的例外指定(C++17まで)noexcept指定(C++17以降)に記述されている例外指定を持ちます。
[編集] 暗黙的に定義されるコピーコンストラクタ
暗黙的に宣言されたコピーコンストラクタが削除されていない場合、それがODR使用されるか定数評価に必要とされる(C++11以降)場合、コンパイラによって定義されます(つまり、関数本体が生成されてコンパイルされます)。共用体型の場合、暗黙的に定義されるコピーコンストラクタは(std::memmoveのように)オブジェクト表現をコピーします。非共用体クラス型の場合、コンストラクタはオブジェクトの直接基底サブオブジェクトとメンバサブオブジェクトを、初期化順序に従って、直接初期化を使用して完全にメンバ単位でコピーします。参照型の非静的データメンバの場合、コピーコンストラクタは、ソース参照がバインドされているのと同じオブジェクトまたは関数に参照をバインドします。
|
これがconstexprコンストラクタ(C++23まで)constexpr関数(C++23以降)の要件を満たす場合、生成されるコピーコンストラクタはconstexprになります。
|
(C++11以降) |
[編集] 削除されたコピーコンストラクタ
クラスTの暗黙的に宣言されたまたは明示的にデフォルト化された(C++11以降)コピーコンストラクタは、次のいずれかの条件が満たされる場合、未定義(C++11まで)削除として定義されます(C++11以降)。
|
(C++11以降) |
-
Tが、クラス型M(またはその多次元配列)の潜在的に構築されるサブオブジェクトを持ち、以下のいずれかを満たす場合。
-
Mが、削除された、または(C++11以降)コピーコンストラクタからアクセス不可能なデストラクタを持つ場合、または Mのコピーコンストラクタを見つけるために適用されるオーバーロード解決が
- 使用可能な候補をもたらさない場合、または
- サブオブジェクトがバリアントメンバである場合、非トリビアルな関数を選択する場合。
-
|
クラス |
(C++11以降) |
[編集] 自明なコピーコンストラクタ
クラスTのコピーコンストラクタは、以下のすべてが真である場合に自明です。
- ユーザー定義されていない(つまり、暗黙的に定義されたかデフォルト化された)場合。
-
Tに仮想メンバ関数がない; -
Tに仮想基底クラスがない; Tの各直接基底に対して選択されたコピーコンストラクタが自明である場合。Tの各非静的クラス型(またはクラス型の配列)メンバに対して選択されたコピーコンストラクタが自明である場合。
非共用体クラスの自明なコピーコンストラクタは、実質的に引数のすべてのスカラサブオブジェクト(再帰的に、サブオブジェクトのサブオブジェクトなども含む)をコピーし、他のアクションは実行しません。ただし、パディングバイトはコピーする必要がなく、コピーされたサブオブジェクトのオブジェクト表現も、その値が同一である限り、同じである必要はありません。
自明にコピー可能 (TriviallyCopyable)なオブジェクトは、std::memmoveなどを用いてオブジェクト表現を直接コピーすることでコピーできます。C言語と互換性のあるすべてのデータ型(POD型)は自明にコピー可能です。
[編集] 適格なコピーコンストラクタ
|
コピーコンストラクタは、ユーザー宣言されているか、または暗黙的に宣言されており定義可能である場合に適格です。 |
(C++11まで) |
|
コピーコンストラクタは、削除されていない場合に適格です。 |
(C++11以降) (C++20まで) |
|
コピーコンストラクタは、以下のすべての条件が満たされる場合に適格です。 |
(C++20以降) |
適格なコピーコンストラクタの自明性は、そのクラスが暗黙的生存期間型であるか、および自明にコピー可能な型であるかを決定します。
[編集] 注記
多くの場合、コピーコンストラクタは観測可能な副作用を生み出す可能性がある場合でも最適化によって省略されます。詳細はコピー省略を参照してください。
[編集] 例
struct A { int n; A(int n = 1) : n(n) {} A(const A& a) : n(a.n) {} // user-defined copy constructor }; struct B : A { // implicit default constructor B::B() // implicit copy constructor B::B(const B&) }; struct C : B { C() : B() {} private: C(const C&); // non-copyable, C++98 style }; int main() { A a1(7); A a2(a1); // calls the copy constructor B b; B b2 = b; A a3 = b; // conversion to A& and copy constructor volatile A va(10); // A a4 = va; // compile error C c; // C c2 = c; // compile error }
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 1353 | C++98 | 暗黙的に宣言されたコピーコンストラクタの条件 未定義であるのは多次元配列型を考慮していなかったため |
これらの型を考慮する |
| CWG 2094 | C++11 | volatile メンバがコピーを非自明にする (CWG issue 496) | トリビアル性は影響を受けない。 |
| CWG 2171 | C++11 | X(X&) = default は非自明であった | 自明になった |
| CWG 2595 | C++20 | コピーコンストラクタは適格ではなかった より制約の厳しい別のコピーコンストラクタが存在する場合 だがその関連する制約を満たさない |
この場合でも適格になりうる。 |