文章目录
- Default initialization默认初始化
- Copy initialization拷贝初始化
- Aggregate initialization聚合初始化
- Direct initialization直接初始化
- list_initialization列表初始化
- value_initialization值初始化
参考:
https://en.cppreference.com/w/cpp/language/copy_initialization
https://en.cppreference.com/w/cpp/language/default_initialization
https://en.cppreference.com/w/cpp/language/aggregate_initialization
https://en.cppreference.com/w/cpp/language/direct_initialization
Default initialization默认初始化
当未指定初始化器(initializer)时,就叫默认初始化。
T object ; (1)
new T (2)
除了以上显示定义的场景之外,基类、非静态成员没有指定初始化器时,都属于默认初始化。
默认初始化会有什么行为呢?
- T的对象类型成员将调用默认构造
- T的非对象类型成员将按照生命周期的不同走不同策略(例如堆栈变量,不做任何初始化操作,其值不确定;对于静态、线程、全局变量,初始化为0)。
需要注意的是,如果是const对象进行默认初始化,需要用户提供一个默认构造函数,编译器提供的默认构造不做数,否则编译报错:
default initialization of an object of const type 'const T1' without a user-provided default constructor
当然,如果对象的所有非静态成员都提供了初始化器,那么也就不需要定义用户默认构造了,因为不属于默认初始化了。
#include <string>
struct T1 { int mem; };
struct T2
{
int mem;
T2() { } // "mem" is not in the initializer list
};
int n; // static non-class, a two-phase initialization is done:
// 1) zero initialization initializes n to zero
// 2) default initialization does nothing, leaving n being zero
int main()
{
int n; // non-class, the value is indeterminate
std::string s; // class, calls default ctor, the value is "" (empty string)
std::string a[2]; // array, default-initializes the elements, the value is {"", ""}
// int& r; // error: a reference
// const int n; // error: a const non-class
// const T1 t1; // error: const class with implicit default ctor
T1 t1; // class, calls implicit default ctor
const T2 t2; // const class, calls the user-provided default ctor
// t2.mem is default-initialized (to indeterminate value)
}
Copy initialization拷贝初始化
用一个对象初始化另一个对象,叫做拷贝初始化,不一定是拷贝构造,也可能是构造。
T object = other; (1)
T object = {other}; (2) (until C++11)
f(other) (3)
return other; (4)
throw object;
catch (T object) (5)
T array[N] = {other-sequence}; (6)
Aggregate initialization聚合初始化
T object = { arg1, arg2, ... }; (1)
T object { arg1, arg2, ... }; (2) (since C++11)
T object = { .des1 = arg1 , .des2 { arg2 } ... }; (3) (since C++20)
T object {.des1 = arg1 , .des2 { arg2 } ... }; (4) (since C++20)
使用初始化列表对聚合类型进行初始化,就叫聚合初始化。
首先,什么是聚合类型?
C++20开始的定义如下:
- 没有用户定义或者继承而来的构造函数
- 没有private、protected的非静态成员(继承而来的可以),注意静态成员是允许的。
- 没有虚基类
- 没有虚含函数
总结下,C++提出聚合类型,初衷是为了适配C语言的结构体,一个聚合类型,其行为必须和C的结构体保持一致。
如下面的base1就是个简单的聚合类型,base2由于用户定义了默认构造函数,将不再是聚合类型。
// aggregate
struct base1 { int b1, b2 = 42; };
// non-aggregate
struct base2
{
base2() : b3(42) {}
int b3;
};
// aggregate in C++17
struct derived : base1, base2 { int d; };
在使用聚合初始化时需要注意,初始化的顺序要按照成员的声明顺序:
struct A { int x; int y; int z; };
A a{.y = 2, .x = 1}; // error; designator order does not match declaration order
A b{.x = 1, .z = 2}; // ok, b.y initialized to 0
这个是cppref说的,我试了下gcc,并没有当作错误处理,只是报了警告:-Wreorder-init-list。
对于联合体,只能提供一个初始化器:
union u { int a; const char* b; };
u f = {.b = "asdf"}; // OK, active member of the union is b
u g = {.a = 1, .b = "asdf"}; // Error, only one initializer may be provided
聚合初始化可以只初始化一部分成员:
struct A
{
std::string str;
int n;
int m = -1;
};
A a{.m = 21}; // Initializes str with {}, which calls the default constructor
// then initializes n with {}
// then initializes m with = 21
未被初始化的成员将使用空{}进行初始化,例如上面的str、n。
聚合初始化支持嵌套:
struct A
{
int x;
struct B
{
int i;
int j;
} b;
} a = {1, {2, 3}}; // initializes a.x with 1, a.b.i with 2, a.b.j with 3
struct base1 { int b1, b2 = 42; };
struct base2
{
base2()
{
b3 = 42;
}
int b3;
};
struct derived : base1, base2
{
int d;
};
derived d1{{1, 2}, {}, 4}; // initializes d1.b1 with 1, d1.b2 with 2,
// d1.b3 with 42, d1.d with 4
derived d2{{}, {}, 4}; // initializes d2.b1 with 0, d2.b2 with 42,
// d2.b3 with 42, d2.d with 4
字符数组的初始化也算是聚合初始化:
char a[] = "abc";
// equivalent to char a[4] = {'a', 'b', 'c', '\0'};
// unsigned char b[3] = "abc"; // Error: initializer string too long
unsigned char b[5]{"abc"};
// equivalent to unsigned char b[5] = {'a', 'b', 'c', '\0', '\0'};
wchar_t c[] = {L"кошка"}; // optional braces
// equivalent to wchar_t c[6] = {L'к', L'о', L'ш', L'к', L'а', L'\0'};
Direct initialization直接初始化
T object = { arg1, arg2, ... }; (1)
T object { arg1, arg2, ... }; (2) (since C++11)
T object = { .des1 = arg1 , .des2 { arg2 } ... }; (3) (since C++20)
T object {.des1 = arg1 , .des2 { arg2 } ... }; (4) (since C++20)
list_initialization列表初始化
value_initialization值初始化
T () (1)
new T () (2)
Class::Class(...) : member () { ... } (3)
T object {}; (4) (since C++11)
T {} (5) (since C++11)
new T {} (6) (since C++11)
Class::Class(...) : member {} { ... } (7) (since C++11)