複製初始化
來自 cppreference.com
用另一個物件初始化一個物件。
目錄 |
[編輯] 語法
T 物件 = 其他; |
(1) | ||||||||
T 物件 = { 其他}; |
(2) | (C++11 前) | |||||||
f( 其他) |
(3) | ||||||||
return 其他; |
(4) | ||||||||
throw 物件;
|
(5) | ||||||||
T 陣列[ N] = { 其他序列}; |
(6) | ||||||||
[編輯] 解釋
複製初始化在以下情況中執行:
1) 當宣告一個非引用型別
T
的具名變數(自動、靜態或執行緒區域性),其初始化器由一個等號後跟一個表示式組成時。3) 當透過值傳遞引數給函式時。
4) 當從按值返回的函式中返回時。
6) 作為聚合初始化的一部分,用於初始化每個提供了初始化器的元素。
複製初始化的效果是:
(C++17 起) |
- 否則,如果
T
是一個類型別,並且 其他 的型別的 cv-unqualified 版本是T
或從T
派生的類,則檢查T
的非 explicit 建構函式,並透過過載決議選擇最佳匹配。然後呼叫該建構函式來初始化物件。
- 否則,如果
T
是一個類型別,並且 其他 的型別的 cv-unqualified 版本不是T
或從T
派生,或者如果T
是非類型別,但 其他 的型別是類型別,則檢查可以將 其他 的型別轉換為T
(如果T
是類型別且存在轉換函式,則轉換為從T
派生的型別)的使用者定義轉換序列,並透過過載決議選擇最佳序列。轉換的結果,如果使用了轉換建構函式,它是一個 cv-unqualified 版本的T
的右值臨時物件(C++11 前)prvalue 臨時物件(C++11 起)(C++17 前)prvalue 表示式(C++17 起),然後用於直接初始化物件。最後一步通常被最佳化掉,轉換的結果直接構造到為目標物件分配的記憶體中,但即使不使用,也需要訪問適當的建構函式(移動或複製)。(C++17 前)
- 否則(如果
T
和 其他 的型別都不是類型別),如有必要,使用標準轉換將 其他 的值轉換為T
的 cv-unqualified 版本。
[編輯] 注意
複製初始化不如直接初始化寬鬆:explicit 建構函式不是轉換建構函式,不考慮用於複製初始化。
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
如果 其他 是一個右值表示式,則在複製初始化期間將透過過載決議選擇並呼叫移動建構函式。這仍然被認為是複製初始化;對於這種情況沒有特殊的術語(例如,移動初始化)。
隱式轉換是根據複製初始化定義的:如果型別為 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: 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++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
CWG 5 | C++98 | 目標型別的 cv-限定符應用於 由轉換建構函式初始化的臨時物件 |
臨時物件未 cv-限定 |
CWG 177 | C++98 | 在類物件複製初始化期間建立的臨時物件的 值類別未指定 |
指定為右值 |