C++11新特性统一初始化

Posted 老虎中的小白Gentle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++11新特性统一初始化相关的知识,希望对你有一定的参考价值。

为什么提出统一初始化?

在C++11之前,程序员,尤其是新手,很容易被如何初始化变量或对象的问题弄糊涂。初始化可以使用圆括号、大括号和赋值操作符(=)。因此,C++11引入了统一初始化的概念,这意味着对于任何初始化,你都可以使用一种通用语法。这个语法使用了大括号。

举一些统一初始化的例子

#include <iostream>
#include <vector>
#include <string>
#include <complex>

using namespace std;



int main()
{
	int i{ 10 }; //等效于 int i = 10;

	int values[]{ 1,2,3 };
	
	vector<int> v{ 0,2,4,6,8 };

	vector<string>cities{ "hello","please give a like","Gentle" };

	complex<double> c{ 4.0, 3.0 }; // 等效于c(4.0,3.0)
	

	return 0;
}

上面是用法,下面是深入其根本探究。

initializer_list<>

其实是利用一个事实:编译器看到{t1,t2…tn}便做出一个initializer_list,它关于一个array<T,n>。调用函数(例如构造函数)时,该array内的元素可被编译器分解逐一传给函数。但若函数参数是个initializer_list,调用者却不能给予数个T参数然后以为它们会被自动转为一个initializer_list传入。

vector<string>cities{ "hello","please give a like","Gentle" };

这形成一个initializer_list,背后有个array<string,3>。调用vector的构造函数时,编译器找到了一个vector的构造函数接受initializer_list。所以容器皆有如此的构造函数。

complex<double> c{ 4.0, 3.0 };

这形成一个initializer_list,背后有个array<double,2>。调用complex构造函数时array内的2个元素被分解传给构造函数。complex并无任何构造函数接受initializer_list。

为了支持用户定义类型的初始化列表的概念,C++11提供了类模板std::initializer_list<>。它可以用于支持按值列表或按你想要处理一列值的任何其他地方。例如:

#include <iostream>

using namespace std;

void print(std::initializer_list<int> vals)
{
	for (auto p = vals.begin(); p != vals.end(); ++p) //一列参数,容器的操作
	{
		std::cout << *p << endl;
	}
}

int main()
{

	print({ 1,3,5,7,9 }); //传入一列参数给print
	
 /*输出的结果如下
 1
 3
 4
 5
 7
 9
 */
	return 0;
}

当构造函数用于指定参数数量和初始化列表时,具有初始化列表的版本是首选的
这句怎么理解呢?看例子:

#include <iostream>

using namespace std;

class P
{
public:
	//part 1
	P(int a, int b)
	{
		cout << "P(int, int), a=" << a << ", b=" << b << endl;
	}
	//part 2
	P(initializer_list<int> initlist)
	{
		cout << "P(initializer_list<int>), values= ";
		for (auto i : initlist)
			cout << i << ' ';
		cout << endl;
	}
};

int main()
{
	P p(77, 5);		//P(int, int), a=77, b=5
	P q{ 77,5 };	//P(initializer_list<int>), values = 77 5
	P r{ 77,5,42 };	//P(initializer_list<int>), values = 77 5 42
	P s = { 77,5 };	//P(initializer_list<int>), values = 77 5
	
	
	return 0;

如果没有初始化列表的构造函数,将调用接受两个int值的构造函数来初始化q和s,而初始化r将无效。

initializer_list<>的原代码

在这里插入图片描述

初始化器列表

初始化器列表强制进行所谓的值初始化,这意味着即使是基本数据类型的局部变量(通常具有未定义的初始值)也被初始化为零(如果是指针,则为nullptr)。

	int i; //未被初始化
	int j{}; //初始化为0
	int *p;	//为被初始化
	int *q{};//被初始化为nullptr

但是请注意,使用大括号是不可能缩小初始化的—减少精度或修改所提供的值

	int x1(5.3); //可以这样,waring:从"double"转换到"int",可能丢失数据
	int x2 = 5.3;//可以这样,waring:从"double"转换到"int",可能丢失数据
	int x3{ 5.0 };//error:从"double"转换到"int"需要收缩转换
	int x4 = { 5.3 };//error:从"double"转换到"int"需要收缩转换
 	char c1{ 7 }; //ok
	char c2{ 9999 }; //error: 从"int"转换到"char"需要收缩转换
	vector<int> v1{ 1,2,4,5 }; //ok
	vector<int> v2{ 1,2.3,4,5.6 };//error:从"double"到"int"进行收缩转换无效```

以上是关于C++11新特性统一初始化的主要内容,如果未能解决你的问题,请参考以下文章

C++11新特性:19—— C++11列表初始化(统一了初始化方式)

C++11新特性统一初始化

C++11新特性之列表初始化

C++11新特性详解

C++ 11 新特性

C++11新特性详解