Namespaces
Variants

Copy constructors

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

コピーコンストラクタは、 コンストラクタ の一種であり、同じクラス型の引数で呼び出すことができ、引数の内容を変更せずにコピーします。

目次

構文

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 - 以下のすべての条件を満たす空でない パラメータリスト :
  • クラス型を T とすると、最初のパラメータは T & const T & volatile T & または const volatile T & 型であり、かつ
  • 他のパラメータがないか、または他のすべてのパラメータが デフォルト引数 を持つ
single-parameter-list - 唯一のパラメータが T & const T & volatile T & または const volatile T & 型であり、デフォルト引数を持たない パラメータリスト
function-body - コピーコンストラクタの 関数本体

説明

1) クラス定義内でのコピーコンストラクタの宣言。
2-4) クラス定義内でのコピーコンストラクタの定義。
3) コピーコンストラクタは明示的にデフォルト化されています。
4) コピーコンストラクタは削除されています。
5,6) クラス定義外でのコピーコンストラクタの定義(クラスは宣言を含まなければならない (1) )。
6) コピーコンストラクタは明示的にデフォルト化されています。
struct X
{
    X(X& other); // コピーコンストラクタ
//  X(X other);  // エラー: 不正なパラメータ型
};
union Y
{
    Y(Y& other, int num = 1); // 複数パラメータを持つコピーコンストラクタ
//  Y(Y& other, int num);     // エラー: `num`にデフォルト引数がありません
};

コピーコンストラクタは、同じ型の別のオブジェクトからオブジェクトが 初期化 される際( 直接初期化 または コピー初期化 )、( オーバーロード解決 がより適切な一致を選択する場合や、呼び出しが 省略 される場合を除き)呼び出されます。これには以下が含まれます:

  • 初期化: T a = b ; または T a ( b ) ; 、ここで b は型 T を持つ;
  • 関数引数の受け渡し: f ( a ) ; 、ここで a は型 T を持ち、 f void f ( T t ) である;
  • 関数の戻り値: return a ; 関数内で、例えば T f ( ) のような関数内で使用され、ここで a は型 T を持ち、 move constructor を持たない場合。

暗黙的に宣言されるコピーコンストラクタ

クラス型に対してユーザー定義のコピーコンストラクタが提供されない場合、コンパイラは常にコピーコンストラクタを非 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 となる。

T がユーザー定義のデストラクタまたはユーザー定義のコピー代入演算子を持つ場合、 暗黙的に定義されるコピーコンストラクタの生成は非推奨である。

(C++11以降)

削除されたコピーコンストラクタ

暗黙的に宣言された または明示的にデフォルト化された (C++11以降) コピーコンストラクタは、以下のいずれかの条件が満たされる場合、 未定義 (C++11以前) 削除定義 (C++11以降) されます:

  • T has a non-static data member of rvalue reference type.
(C++11以降)
  • M は以下のいずれかの条件を満たす場合: 削除されたデストラクタを持つ、または (C++11以降) コピーコンストラクタからアクセス不能なデストラクタを持つ、あるいは
  • M のコピーコンストラクタ探索に対するオーバーロード解決が
  • 有効な候補を結果として生成しない場合、または
  • サブオブジェクトが バリアントメンバ である場合に非トリビアルな関数を選択する場合。

クラス T の暗黙的に宣言されるコピーコンストラクタは、 T move constructor または move assignment operator を宣言している場合、削除済みとして定義される。

(C++11以降)

自明なコピーコンストラクタ

T クラスのコピーコンストラクタは、以下のすべての条件を満たす場合にトリビアルとなります:

  • ユーザー提供ではない(つまり、暗黙的に定義されるかデフォルト化されている);
  • T に仮想メンバ関数がない;
  • T に仮想基底クラスがない;
  • T のすべての直接基底クラスに対して選択されるコピーコンストラクタがトリビアルである;
  • T のすべての非静的クラス型(またはクラス型の配列)メンバに対して選択されるコピーコンストラクタがトリビアルである;

非共用体クラスの自明なコピーコンストラクタは、引数のすべてのスカラー部分オブジェクト(再帰的に、部分オブジェクトの部分オブジェクトなどを含む)を効果的にコピーし、それ以外のアクションを実行しません。ただし、パディングバイトはコピーする必要はなく、コピーされた部分オブジェクトのオブジェクト表現は、それらの値が同一である限り、同じである必要はありません。

TriviallyCopyable オブジェクトは、オブジェクト表現を手動でコピーすることによって複製できます。例えば、 std::memmove を使用する場合などです。C言語と互換性のあるすべてのデータ型(POD型)は、自明にコピー可能です。

有効なコピーコンストラクタ

コピーコンストラクタは、ユーザー宣言されているか、暗黙的に宣言されかつ定義可能である場合に適格となる。

(C++11まで)

コピーコンストラクタは、削除されていない場合に適格となる。

(C++11以降)
(C++20まで)

コピーコンストラクタは、以下の条件をすべて満たす場合に適格となる:

  • 削除されていないこと。
  • その 関連制約 (存在する場合)が満たされていること。
  • 関連制約が満たされているコピーコンストラクタのうち、 より制約された ものが存在しないこと。
(C++20以降)

有効なコピーコンストラクタの自明性は、クラスが implicit-lifetime type であるかどうか、およびクラスが trivially copyable type であるかどうかを決定します。

注記

多くの状況において、コピーコンストラクタは、観測可能な副作用を生じる場合であっても最適化によって除去されます。詳細は copy elision を参照してください。

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 1353 C++98 暗黙的に宣言されるコピーコンストラクタが未定義となる条件に
多次元配列型が考慮されていなかった
これらの型を考慮する
CWG 2094 C++11 volatileメンバーがコピーを非トリビアルにしていた ( CWG issue 496 ) トリビアル性に影響しない
CWG 2171 C++11 X ( X & ) = default が非トリビアルだった トリビアルに変更
CWG 2595 C++20 より制約されているが関連制約を満たさない
別のコピーコンストラクタが存在する場合、
コピーコンストラクタが適格ではなかった
この場合でも適格となりうる

関連項目