名前空間
変種
操作

コピー初期化

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

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

目次

[編集] 構文

T object = other; (1)
T object = {other}; (2) (C++11まで)
f(other) (3)
return other; (4)
throw object;

catch (T object)

(5)
T array[N] = {other-sequence}; (6)

[編集] 説明

コピー初期化は次の状況で行われます。

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

コピー初期化の効果は次のとおりです。

  • まず、T がクラス型であり、初期化子がその cv-unqualified 型が T と同じクラスであるprvalue 式である場合、そこから実体化された一時オブジェクトではなく、初期化子式自体が目的のオブジェクトを初期化するために使用されます。コピーエリジョンを参照してください。
(C++17以降)
  • それ以外の場合、T がクラス型であり、other の型の cv-unqualified バージョンが T または T から派生したクラスである場合、T非明示的コンストラクタが調べられ、オーバーロード解決によって最適なものが選択されます。そのコンストラクタが呼び出されてオブジェクトが初期化されます。
  • それ以外の場合、T がクラス型であり、other の型の cv-unqualified バージョンが T または T から派生したものではない場合、または T が非クラス型であるが other の型がクラス型である場合、other の型から T (または T がクラス型で変換関数が利用できる場合は T から派生した型) に変換できるユーザー定義変換シーケンスが調べられ、オーバーロード解決によって最適なものが選択されます。変換の結果、つまり、変換コンストラクタが使用された場合は T の cv-unqualified バージョンのrvalue一時オブジェクト(C++11まで)prvalue一時オブジェクト(C++11以降)(C++17まで)prvalue式(C++17以降)は、オブジェクトを直接初期化するために使用されます。最後のステップは通常最適化され、変換の結果はターゲットオブジェクトに割り当てられたメモリに直接構築されますが、適切なコンストラクタ (ムーブまたはコピー) は使用されない場合でもアクセス可能である必要があります。(C++17まで)
  • それ以外の場合 (Tother の型もクラス型ではない場合)、必要に応じて、other の値を T の cv-unqualified バージョンに変換するために標準変換が使用されます。

[編集] 注記

コピー初期化は直接初期化よりも許容範囲が狭く、明示的コンストラクタ変換コンストラクタではなく、コピー初期化では考慮されません。

struct Exp { explicit Exp(const char*) {} }; // not convertible from const char*
Exp e1("abc");  // OK
Exp e2 = "abc"; // Error, copy-initialization does not consider explicit constructor
 
struct Imp { Imp(const char*) {} }; // convertible from const char*
Imp i1("abc");  // OK
Imp i2 = "abc"; // OK

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

struct S { S(std::string) {} }; // implicitly convertible from std::string
S s("abc");   // OK: conversion from const char[4] to std::string
S s = "abc";  // Error: no conversion from const char[4] to S
S s = "abc"s; // OK: conversion from std::string to S

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

暗黙的な変換はコピー初期化に関して定義されています。つまり、型 T のオブジェクトが式 E でコピー初期化できる場合、ET に暗黙的に変換可能です。

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

[編集]

#include <memory>
#include <string>
#include <utility>
 
struct A
{
    operator int() { return 12;}
};
 
struct B
{
    B(int) {}
};
 
int main()
{
    std::string s = "test";        // OK: constructor is non-explicit
    std::string s2 = std::move(s); // this copy-initialization performs a move
 
//  std::unique_ptr<int> p = new int(1); // error: constructor is explicit
    std::unique_ptr<int> p(new int(1));  // OK: direct-initialization
 
    int n = 3.14;    // floating-integral conversion
    const int b = n; // const doesn't matter
    int c = b;       // ...either way
 
    A a;
    B b0 = 12;
//  B b1 = a;       // < error: conversion from 'A' to non-scalar type 'B' requested
    B b2{a};        // < identical, calling A::operator int(), then B::B(int)
    B b3 = {a};     // <
    auto b4 = B{a}; // <
 
//  b0 = a;         // < error, assignment operator overload needed
 
    [](...){}(c, b0, b3, b4); // pretend these variables are used
}

[編集] 欠陥報告

以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。

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

[編集] 関連項目

English 日本語 中文(简体) 中文(繁體)