C++ 列表初始化

C++ 列表初始化

C++11 中,引入了用 {} 执行初始化的统一形式,C++11 称这种形式为统一初始化(Uniform initialization)

使用这种形式,可以解决所谓的“C++最令人恼怒的解析问题”

最令人恼怒的解析问题

该问题源于函数风格的转型和函数声明之间的相似性,导致很多代码都会被看做是函数声明

考虑这段代码

ifstream dataFile("ints.dat");
list<int> data(istream_iterator<int>(dataFile), istream_iterator<int>());

原意是用一对流迭代器去初始化列表,但运行后你会发现,它什么都没有做

原因在于编译器会认为 data 是一个函数

  • 第一个参数 dataFile 是 istream_iterator<int> 类型的对象
  • 第二个参数是不接受参数,返回 istream_iterator<int> 对象的函数

因为在函数声明中

  • 包裹形参名的圆括号会被无视
  • int f(double d);int f(double (d)); 是等价的
    • 参数是 double 类型的 d
  • 空的圆括号会被认为是这里有一个函数类型的参数
    • int g(double ());
    • 参数是返回值为 double,参数为空的函数
class Widget
{
    //假设Widget有默认构造器
};

Widget w();

在这个例子中,w 并不是 Widget 对象,而是返回值为 Widget 类型的函数

C++ 11 前的解决方案

将参数声明包裹到圆括号里是非法的,但将函数调用的参数包裹在圆括号里是合法的:

list<int> data((istream_iterator<int>(dataFile)), istream_iterator<int>());

一种可读性更好、更合理的方式:

ifstream dataFile("ints.dat");
istream_iterator<int> begin(dataFile);
istream_iterator<int> end;
list<int> data(begin, end);

列表初始化

用列表初始化来解决上面的问题

list<int> data{ istream_iterator<int>{dataFile}, istream_iterator<int>{} };

Obj(1.0)Obj{1.0} 的一个区别是:前者允许调用 Obj(int),而列表初始化不允许存在精度损失的类型转换

列表初始化的限制

列表初始化主要的限制是,如果一个类既有使用初始化列表的构造函数,又有不使用初始化列表的构造函数,那编译器会千方百计地试图调用使用初始化列表的构造函数,导致各种意外

vector<int> v{3, -1};
for (auto i : v) {
	cout << i << endl;
}

比如上面的代码,可能本意是构造一个 3 个元素,初始值都是 -1 的 vector,但编译器会去尝试调用列表初始化构造函数,构造一个 [3, -1] vector 出来

对此,比较好的做法是:

  • 如果一个类没有使用初始化列表的构造函数时,初始化该类对象可全部使用统一初始化语法
  • 如果一个类有使用初始化列表的构造函数时,则只应用在初始化列表构造的情况

initializer_list

initializer_list 定义在同名头文件中

template< class T >  
class initializer_list;

initializer_list 是一种轻量级的代理对象,用来访问 T 类型的对象数组

  • 可以实现为一对指针,或指针加数组长度
  • initializer_list 对象被拷贝时,底层数组不会被拷贝
  • 底层数组是 const T[N] 类型的临时数组
    • 每个元素都是从 {} 列表中拷贝来的
    • initializer_list 对象中的元素永远是常量值,无法被修改
  • 有点像 string_view 或 asio 中的 buffer

在以下几种情况中, initializer_list 对象会被自动构造

  • {} 列表初始化对象,且该对象的构造函数接受 initializer_list 参数
    • 标准库容器基本都会接受 initializer_list<value_type> 类型的参数
    • 因此标准库容器基本都是可以使用列表初始化的
  • {} 列表作为赋值语句的右操作数/函数的参数,对应的赋值运算符/函数接受 initializer_list 参数
posted @ 2022-02-23 21:11  路过的摸鱼侠  阅读(742)  评论(0编辑  收藏  举报