名前空間
変種
操作

コピー初期化

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定 (C++20未満)
noexcept 指定子 (C++11)
例外
名前空間
指定子
decltype (C++11)
auto (C++11)
alignas (C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr (C++11)
ユーザ定義 (C++11)
ユーティリティ
属性 (C++11)
typedef 宣言
型エイリアス宣言 (C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

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

目次

[編集] 構文

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}; (6)

[編集] 説明

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

1) 非参照型 T の名前付き変数 (自動、静的、またはスレッドローカル) が等号とそれに続く式から構成される初期化子付きで宣言されたとき。
2) (C++11未満)スカラー型 T の名前付き変数が等号とそれに続く波括弧で囲まれた式から構成される初期化子付きで宣言されたとき (ノート: C++11 以降、これはリスト初期化に分類され、ナローイング変換は許容されません)。
3) 関数に値で引数を渡すとき。
4) 値で返す関数から戻るとき。
5) 例外を値で投げるまたはキャッチするとき。
6) 集成体初期化の一部として、初期化子が提供されるそれぞれの要素を初期化するため。

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

  • まず、 T がクラス型であり、初期化子が prvalue であり、その prvalue の cv 修飾されていない型が T と同じクラスの場合、その初期化子の式自身 (それから具体化された一時オブジェクトではなく) が宛先のオブジェクトを初期化するために使用されます。 コピー省略を参照してください。
(C++17以上)
  • T がクラス型であり、 other の型の cv 修飾されていないバージョンが T または T から派生したクラスの場合、 T非 explicit コンストラクタが調べられ、オーバーロード解決によりベストマッチが選択されます。 そしてそのコンストラクタがそのオブジェクトを初期化するために呼ばれます。
  • T がクラス型であり、 other の型の cv 修飾されていないバージョンが T または T からの派生でない場合、または T は非クラス型だけれども other の型がクラス型の場合、 other の型から T (または T がクラス型で変換関数が利用可能な場合は T から派生した型) への変換が可能なユーザ定義変換シーケンスが調べられ、オーバーロード解決を通してベストなものが選択されます。 そして、その変換の結果 (変換コンストラクタが使用された場合、これは prvalue の一時オブジェクト (C++17未満)prvalue 式 (C++17以上)です) がそのオブジェクトを直接初期化するために使用されます。 この最後のステップは、通常、最適化によって除去され、変換の結果はターゲットオブジェクトのために確保されたメモリ内に直接構築されます。 しかし、たとえ使用されなくとも、適切なコンストラクタ (ムーブまたはコピー) は要求されます。 (C++17未満)
  • そうでなければ (Tother の型もクラス型でない場合)、 other の値を T の cv 修飾されていないバージョンに変換するために、必要であれば、標準変換が使用されます。

[編集] ノート

コピー初期化は直接初期化よりも非寛容です。 explicit コンストラクタ変換コンストラクタでなく、コピー初期化に対しては考慮されません。

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 が右辺値式の場合は、ムーブコンストラクタがオーバーロード解決によって選択され、コピー初期化中に呼ばれます。 ムーブ初期化とかいうような用語はありません。

暗黙の変換はコピー初期化によって定義されます。 T 型のオブジェクトが式 E を用いてコピー初期化可能な場合、 ET に暗黙に変換可能です。

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

[編集]

#include <string>
#include <utility>
#include <memory>
 
struct A 
{
  operator int() { return 12;}
};
 
struct B 
{
  B(int) {}
};
 
int main()
{
    std::string s = "test"; // OK、コンストラクタは explicit ではありません
    std::string s2 = std::move(s); // このコピー初期化はムーブを行います
 
//  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; // エラー、代入演算子のオーバーロードが必要です
}


[編集] 関連項目