Namespaces
Variants

Copy-initialization

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

別のオブジェクトからオブジェクトを初期化します。

目次

構文

T オブジェクト = 他のオブジェクト ; (1)
T オブジェクト = { 他のオブジェクト }; (2) (C++11以前)
関数f ( 他のオブジェクト ) (3)
return 他のオブジェクト ; (4)
throw オブジェクト ;

catch ( T オブジェクト )

(5)
T 配列 [ N ] = { 他のシーケンス }; (6)

説明

コピー初期化は以下の状況で実行されます:

1) 非参照型 T の名前付き変数(自動、静的、またはスレッドローカル)が、等号とそれに続く式からなる初期化子で宣言された場合。
2) (C++11まで) スカラ型 T の名前付き変数が、等号とそれに続く波括弧で囲まれた式からなる初期化子で宣言される場合(注: C++11以降、これは リスト初期化 として分類され、縮小変換は許可されません)。
3) 関数に引数を 値渡し で渡す場合。
4) 値を返す関数から returning する場合。
5) 例外を値で throwing または catching する場合。
6) 集約初期化の一部として、 aggregate initialization において、初期化子が提供されている各要素を初期化するため。

コピー初期化の効果は以下の通りです:

  • まず、 T がクラス型であり、初期化子が T と同じクラスであるCV修飾されていない型の prvalue 式である場合、一時オブジェクトからマテリアライズされるのではなく、初期化子式自体が宛先オブジェクトの初期化に使用されます: copy elision を参照してください。
(C++17以降)
  • 最初に (C++17まで) それ以外の場合 (C++17以降) T がクラス型であり、 other の型のCV修飾されていないバージョンが T または T から派生したクラスである場合、 T 非明示的コンストラクタ が調べられ、オーバーロード解決によって最適な一致が選択されます。その後、そのコンストラクタがオブジェクトの初期化のために呼び出されます。
  • それ以外の場合、 T がクラス型であり、かつ other の型のCV修飾なしバージョンが T または T から派生した型でない場合、または T が非クラス型であるが other の型がクラス型である場合、 ユーザー定義変換シーケンス が調査され、 other の型から T (または T がクラス型で変換関数が利用可能な場合は T から派生した型)へ変換可能な最適なものがオーバーロード解決を通じて選択される。変換の結果は、 右値一時オブジェクト (C++11まで) 純粋右値一時オブジェクト (C++11から) (C++17まで) 純粋右値式 (C++17から) であり、 変換コンストラクタ が使用された場合は T のCV修飾なしバージョンの一時オブジェクトが生成され、その後 直接初期化 によってオブジェクトが初期化される。 最終ステップは通常 最適化により省略 され、変換結果は対象オブジェクト用に確保されたメモリに直接構築されるが、適切なコンストラクタ(ムーブまたはコピー)は使用されない場合でもアクセス可能である必要がある。 (C++17まで)
  • それ以外の場合( T other の型のいずれもクラス型でない場合)、必要に応じて 標準変換 を使用して、 other の値を T のCV修飾なしバージョンに変換します。

注記

コピー初期化は直接初期化よりも制限が厳しい: explicitコンストラクタ convertingコンストラクタ ではなく、コピー初期化では考慮されない。

struct Exp { explicit Exp(const char*) {} }; // const char* からの変換不可
Exp e1("abc");  // OK
Exp e2 = "abc"; // エラー、コピー初期化では explicit コンストラクタを考慮しない
struct Imp { Imp(const char*) {} }; // const char* からの変換可能
Imp i1("abc");  // OK
Imp i2 = "abc"; // OK

さらに、コピー初期化における暗黙変換は初期化子から直接 T を生成しなければならないのに対し、例えば直接初期化では初期化子から T のコンストラクタの引数への暗黙変換が期待されます。

struct S { S(std::string) {} }; // std::stringからの暗黙変換が可能
S s("abc");   // OK: const char[4]からstd::stringへの変換
S s = "abc";  // エラー: const char[4]からSへの変換は不可
S s = "abc"s; // OK: std::stringからSへの変換

other が右辺値式である場合、 move constructor がオーバーロード解決によって選択され、コピー初期化中に呼び出されます。これは依然としてコピー初期化と見なされます。このケースに対する特別な用語(例:ムーブ初期化)はありません。

暗黙の変換 はコピー初期化の観点から定義されます: 型 T のオブジェクトが式 E でコピー初期化可能な場合、 E T へ暗黙的に変換可能です。

等号、 = 、は名前付き変数のコピー初期化において、代入演算子とは関係ありません。代入演算子のオーバーロードはコピー初期化に影響を与えません。

#include <memory>
#include <string>
#include <utility>
struct A
{
    operator int() { return 12;}
};
struct B
{
    B(int) {}
};
int main()
{
    std::string s = "test";        // OK: コンストラクタは非explicit
    std::string s2 = std::move(s); // このコピー初期化はmoveを実行
//  std::unique_ptr<int> p = new int(1); // エラー: コンストラクタはexplicit
    std::unique_ptr<int> p(new int(1));  // OK: 直接初期化
    int n = 3.14;    // 浮動小数点-整数変換
    const int b = n; // constは影響しない
    int c = b;       // ...どちらの場合も同様
    A a;
    B b0 = 12;
//  B b1 = a;       // < エラー: 'A'から非スカラー型'B'への変換が要求されました
    B b2{a};        // < 同等、A::operator int()を呼び出し、その後B::B(int)を呼び出し
    B b3 = {a};     // <
    auto b4 = B{a}; // <
//  b0 = a;         // < エラー、代入演算子のオーバーロードが必要
    [](...){}(c, b0, b3, b4); // これらの変数が使用されていることを仮定
}

不具合報告

以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。

DR 適用対象 公開時の動作 正しい動作
CWG 5 C++98 変換コンストラクタによって初期化される一時オブジェクトに
宛先型のcv修飾が適用される
一時オブジェクトはcv修飾されない
CWG 177 C++98 クラスオブジェクトのコピー初期化中に作成される一時オブジェクトの
値カテゴリが未規定
右辺値として規定

関連項目