直接初始化
出自cppreference.com
以一組明確的構造函數實參對對象進行初始化。
語法
T 對象 ( 實參 );
T 對象 |
(1) | ||||||||
T 對象 { 實參 };
|
(2) | (C++11 起) | |||||||
T ( 其他對象 )
T |
(3) | ||||||||
static_cast< T >( 其他對象 )
|
(4) | ||||||||
new T(實參列表, ...)
|
(5) | ||||||||
類::類() : 成員(實參列表, ...) { ... }
|
(6) | ||||||||
[實參](){ ... }
|
(7) | (C++11 起) | |||||||
解釋
在下列場合進行直接初始化:
1) 以表達式或花括號初始化列表(C++11 起)的非空帶括號列表初始化。
2) 以花括號環繞的單個初始化器初始化一個非類類型對象(注意:對於類類型和其他使用花括號初始化列表的初始化,見列表初始化)。
5) 用帶有非空初始化器的 new 表達式初始化具有動態存儲期的對象。
6) 用構造函數初始化器列表初始化基類或非靜態成員。
7) 在 lambda 表達式中從按複製捕獲的變量初始化閉包對象的成員。
直接初始化的效果是:
- 如果
T是數組類型,那麼
|
(C++20 前) |
struct A
{
explicit A(int i = 0) {}
};
A a[2](A(1)); // OK:以 A(1) 初始化 a[0] 并以 A() 初始化 a[1]
A b[2]{A(1)}; // 错误:从 {} 隐式复制初始化 b[1] 选择了 explicit 构造函数
|
(C++20 起) |
- 如果
T是類類型,
| (C++17 起) |
- 檢驗
T的構造函數並由重載決議選取最佳匹配。然後調用該構造函數以初始化對象。
- 檢驗
struct B
{
int a;
int&& r;
};
int f();
int n = 10;
B b1{1, f()}; // OK:延长生存期
B b2(1, f()); // 良构,但有悬垂引用
B b3{1.0, 1}; // 错误:窄化转换
B b4(1.0, 1); // 良构,但有悬垂引用
B b5(1.0, std::move(n)); // OK
|
(C++20 起) |
- 否則,如果
T是非類類型但源類型是類類型,則檢驗源類型及其各基類的轉換函數,並由重載決議選取最佳匹配。然後用選取的用戶定義轉換,將初始化器表達式轉換為所初始化的對象。 - 否則,如果
T是bool而原類型是 std::nullptr_t,則被初始化對象的值為false。 - 否則,在必要時使用標準轉換,轉換 其他對象 的值為
T的無 cv 限定版本,而所初始化的對象的初值為(可能為轉換後的)該值。
註解
直接初始比複製初始化更寬鬆:複製初始化僅考慮非顯式的構造函數和非顯式的用戶定義轉換函數,而直接初始化考慮所有構造函數和所有用戶定義轉換函數。
在使用直接初始化語法 (1)(帶圓括號)的變量聲明和函數聲明之間有歧義的情況下,編譯器始終選擇函數聲明。此消歧義規則有時是反直覺的,並且已被稱為最煩人的分析。
運行此代碼
#include <fstream>
#include <iterator>
#include <string>
int main()
{
std::ifstream file("data.txt");
// 下面是函数声明:
std::string foo1(std::istreambuf_iterator<char>(file),
std::istreambuf_iterator<char>());
// 它声明名为 str 的函数,其返回类型为 std::string,
// 第一参数拥有 std::istreambuf_iterator<char> 类型和名称 "file"
// 第二参数无名称并拥有类型 std::istreambuf_iterator<char>(),
// 它被重写成函数指针类型 std::istreambuf_iterator<char>(*)()
// C++11 前的修正(用以声明变量):用额外括号环绕其中一个实参
std::string str1((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
// C++11 后的修正(用以声明变量):对任意实参使用列表初始化
std::string str2(std::istreambuf_iterator<char>{file}, {});
}
示例
運行此代碼
#include <iostream>
#include <memory>
#include <string>
struct Foo
{
int mem;
explicit Foo(int n) : mem(n) {}
};
int main()
{
std::string s1("test"); // 自 const char* 的构造函数
std::string s2(10, 'a');
std::unique_ptr<int> p(new int(1)); // OK:允许 explicit 构造函数
// std::unique_ptr<int> p = new int(1); // 错误:构造函数为 explicit
Foo f(2); // f 被直接初始化:
// 构造函数形参 n 从右值 2 复制初始化
// f.mem 从形参 n 直接初始化
// Foo f2 = 2; // 错误:构造函数为 explicit
std::cout << s1 << ' ' << s2 << ' ' << *p << ' ' << f.mem << '\n';
}
輸出:
test aaaaaaaaaa 1 2