C++初始化

  • 默认初始化
    这是在不使用初始化器构造变量时执行的初始化

  • 使用初始化器进行初始化
    按照语境,初始化器可以调用:

  • 值初始化,例如 std::string s{};
    这是在变量以空初始化器构造时进行的初始化。

  • 直接初始化,例如 std::string s(“hello”);
    从构造函数参数的显式集合初始化对象

  • 复制初始化,例如 std::string s = “hello”;
    从另一对象初始化对象

  • 列表初始化,例如 std::string s{‘a’, ‘b’, ‘c’};
    从花括号初始化器列表初始化对象

  • 聚合初始化,例如 char a[3] = {‘a’, ‘b’};
    从花括号初始化器列表初始化聚合体
    聚合初始化是一种初始化聚合体的列表初始化

  • 引用初始化,例如 char& c = a[0];
    绑定引用到对象
    包括左值引用的初始化和右值引用的初始化

  • 静态初始化

  1. 若受允许,则首先发生常量初始化(这些情形见常量初始化)。 实践上,常量初始化通常在编译期进行,而预计算的对象表示作为程序映像的一部分存储。若编译器没有这么做,则亦保证此初始化发生先于任何动态初始化。
  2. 对于所有其他 非局部 静态 及 线程局域变量 ,发生零初始化。 实现中,要被零初始化的变量置于程序映像的 .bss 段,它不占据磁盘空间,并在加载程序时为操作系统以零填充。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;


struct T1
{
int mem1;
std::string mem2;
}; // 隐式默认构造函数

struct T2
{
int mem1;
std::string mem2;
T2(const T2&) { } // 用户提供的复制构造函数
}; // 无默认构造函数

struct T3
{
int mem1;
std::string mem2;
T3() { } // 用户提供的默认构造函数
};

struct Foo {
int mem;
explicit Foo(int n) : mem(n) {}
};

int x1; // 静态非类,进行二段初始化: 1) 零初始化初始化 n 为零 2) 默认初始化不做任何事,令 n 为零

int main(int argc, char *argv[])
{
//// 默认初始化 一般是定义变量后未进行任何的操作则触发

int i11; // 默认初始化 非类 值不确定
int* a11 = new int[10]; // 数组 => 每个元素 默认初始化 每个元素的值为不确定
string str11; // 默认初始化 类,调用默认构造函数,值是 "" (空字符串)

// int& r; // 错误:引用
// const int n; // 错误: const 的非类 必须初始化
// const T1 t1; // 错误: const 类带隐式默认构造函数 无法初始化 必须用户提供显式默认构造函数

T1 t11; // 类:调用隐式默认构造函数 t1.mem1 值初始化为未确定
const T3 t13; // const 类,调用用户提供的默认构造函数 t3.mem1 被默认初始化(为不确定值)


//// 值初始化 有 () {} 两种空括号形式会触发 值初始化
int n{}; // 标量 => 零初始化,值为 0
double f = double(); // 标量 => 零初始化,值为 0.0
int* a21 = new int[10](); // 数组 => 每个元素的值初始化 每个元素的值为 0


T1 t21{}; // 有隐式默认构造函数的类 => t1.mem1 被零初始化,值为 0 t1.mem2 被默认初始化,值为 ""
// T2 t22{}; // 错误:类无默认构造函数
T3 t23{}; // 有用户提供默认构造函数的类 => t3.mem1 被默认初始化为不确定值 t3.mem2 被默认初始化,值为 ""
std::vector<int> v21(3); // 值初始化每个元素 每个元素的值为 0


//// 直接初始化 直接调用构造函数的形式会触发直接初始化 以 object(kkk) new object(kkk) object():men(kkk)(构造函数初始化器列表) [arg](){} 等形式触发
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 会阻止复制初始化的发生


//// 复制初始化 以( 等号 传参 抛出异常 返回值 )的形式用一个对象初始化另一个对象
//// explicit 可以禁止复制初始化的发生
// std::unique_ptr<int> p = new int(1); // 错误:unique_ptr 构造函数为 explicit 试图进行复制初始化
std::unique_ptr<int> p(new int(1)); // OK :直接初始化

//// 列表初始化 以花括号的形式触发 一般触发列表初始化后 会触发 复制初始化( obj ttt={kkk} )或者是值初始化( obj({kkk}) )
double d = double{1.2}; // 临时量的列表初始化,然后复制初始化
std::map<int, std::string> m = { // 嵌套列表初始化
{1, "a"},
{2, {'a', 'b', 'c'} },
{3, s1}
};

return 0;
}
T B
站点访问量: / , 本页阅读量:
T B