《Effective Modern C++》学习笔记之条款七:在创建对象时注意区分()和{}

C++11为解决C++98对象初始化语法繁杂问题,引入统一初始化(大括号初始化)。它能处理C++98无法完成的工作,如初始化STL容器、指定类非静态成员默认值等。使用大括号初始化还可避免解析语法问题,但在类有std::initializer_list<T>重载函数时,匹配规则较复杂。

C++98中对象初始化的方式眼花缭乱,所以为了解决众多初始化语法带来的疑惑,也为了进一步覆盖所有初始化场景,C++11新引入了统一初始化:单一的,至少从概念上可以用于一切场合,表达一切意思的初始化,也被称为大括号初始化。

目前常见的初始化方式大概有以下几种:

int x(0);    //使用小括号初始化
int y = 0;   //使用等号初始化
int z{0};    //使用C++11新引入的统一初始化格式,即大括号初始化
int z1 = {0};//统一初始化格式变体,编译器对其处理完全无差别

C++11新引入了统一初始化方式可以处理很多C++98无法完成的工作,例如:

(1)给一个STL容器初始化为持有特定集合:

std::vector<int> v{1,3,5};

(2)为类的非静态成员变量指定默认初始化值:

class Widget {

private:
    int x{0};   //可行,C++11统一初始化
    int y = 0;  //可行,使用赋值语句赋值
    int z(0);   //不可行

}

(3)为不可复制的对象进行初始化,例如std::atomic型别对象,不支持等号运算符,所以不得不使用()或者{}进行初始化:

std::atomic<int> x1{0};  //可行
std::atomic<int> x1(0);  //可行
std::atomic<int> x1 = 0; //不可行

(4)禁止内建型别之间进行隐式窄化型别转换:

double x = 2.3;

int sum{x};   //编译报错,会进行窄化转换检查

int sum2 = x; //编译告警,直接丢弃x的小数位

int sum3(x);  //编译告警,直接丢弃x的小数位

(5)对解析语法免疫

C++规定,任何能够解析为声明的都要解析为声明,而这会带来副作用,程序员本来想以默认方式构造一个对象,却不小心被编译器解释为声明了一个函数,但使用大括号初始化方式则可以避免这类问题,例如:

// 本意是调用Widget的默认构造函数,声明一个对象
// 结果却变成了声明了一个函数w1
Widget w1();

// 函数声明无法使用大括号指定形参
// 结果只能为Widget 对象
Widget w2{};

条款2时,我们就说过,如果使用auto来接收大括号初始化的变量,那么auto将被推导为std::initializer_list类型,所以使用大括号作为函数形参时,其类型是:std::initializer_list<T>。

正常情况下是不会有什么问题,但是如果类的声明中包含了一个形参为std::initializer_list<T>的重载函数,则该函数就会匹配所有大括号的型别,具体会分以下几种情况进行处理:

  • 1、std::initializer_list<T>类型完全匹配,则直接调用该重载函数
  • 2、若实参需要提升,则先提升后匹配
  • 3、若实参需要窄化才能匹配,则编译报错
  • 3、如果实参完全不可能匹配到std::initializer_list<T>中的类型,则判断是否又满足该类型的其他重载函数
class Widget {
public:
   Widget(string i,double b);
   Widget(std::initializer_list<long,double> t);

}


long l = 0;
double d = 1.0;
Widget w1{l,d};  //完全匹配,正确调用第二个构造函数

int i = 0;
Widget w2{i,d};  //类型提升,将i提升为long类型后,匹配第二个



long long ll = 0;
Widget w2{ll,d};  //需要窄化,编译器将报错

string s = “123”;
Widget w2{s,d};  //从string不可能转换为long,将匹配第一个重载函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chiang木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值