C++11:初始化

  初始化是一个非常重要的语言特性,最常见的就是对对象进行初始化。在传统 C++ 中,不同的对象有着不同的初始化方法,例如普通数组、POD (plain old data,没有构造、析构和虚函数的类或结构体)类型都可以使用 {} 进行初始化,也就是我们所说的初始化列表。而对于类对象的初始化,要么需要通过拷贝构造、要么就需要使用 () 进行。这些不同方法都针对各自对象,不能通用。

类内成员初始化

class Base {
public:
	Base(int i) :x(i) {} //初始化列表给x初始化
public:
	int x;
};

class Base2 {
public:
	Base2() {}
public:
	int x = 1;
	Base base{ 2 };// 对象成员,创建对象时,可以使用{}来调用构造函数
	string name{ "mike" };
};

列表初始化

  C++ 11 扩大了用大括号括起的列表(初始化列表 std::initializer_list)的适用范围,使其可以用于所有内置类型和用户定义的类型(即类对象)。使用初始化列表时,可添加 = 也可不添加

int x = { 5 };  //可以用于初始化单一变量,数组以及new运算符
double y = { 2.75 };
int arr[5]{ 1,2,3,4,5 };
int *ar = new int[5]{ 1,2,3,4,5 };

初始化列表可以用于初始化结构体类型

struct Node {
	string name;
	int age;
};

Node s1{ "make" , 25 };

其他一些不方便初始化的地方使用,比如 std 的初始化,如果不使用这种方式,只能用构造函数来初始化,难以达到效果:

std::vector<int> ivec1(3, 5);  
std::vector<int> ivec2 = {5, 5, 5};  
std::vector<int> ivec3 = {1,2,3,4,5}; //不使用列表初始化用构造函数难以实现  

std::initializer_list

  C++ 11提供了模板类 initializer_list ,可以将其用作构造函数的参数。如果类有接收initializer_list 作为参数的构造函数,则初始化列表语法就只能用于构造函数。列表中的元素必须是同一种类型或可以转换为同一种类型。

#include <iostream>
#include <initializer_list>
using namespace std;

double sum(initializer_list<double> il) {
	double ret = 0;
	for (auto it = il.begin(); it != il.end(); it++)
		ret += *it;
	return ret;
}

int main() {
	double ans = sum({ 1.1, 2.2, 3.3, 4.4 });
	cout << ans << endl;
}

防止类型收窄

  类型收窄指的是导致数据内容发生变化或者精度丢失的隐式类型转换。使用列表初始化可以防止类型收窄。

int main() {
	const int x = 1024;
	const int y = 10;
	
	char a = x;// 收窄,但可以通过编译
	char* b = new char(1024);// 收窄,但可以通过编译

	char c = { x };// err, 收窄,无法通过编译
	char d = { y };
	unsigned char e{ -1 };      // err,收窄,无法通过编译

	float f{ 7 };// 可以通过编译
	int g{ 2.0f }; // err,收窄,无法通过编译
	float* h = new float{ 1e20 };  // err,收窄,无法通过编译
	float i = 1.2l;                 // 可以通过编译
	return 0;
}

VS 2019错误提示:
image.png