C++ 初始化列表构造函数VS普通构造函数

普通构造函数VS初始化列表构造函数#

初始化列表构造函数最优先匹配问题#

对于一个类而言,只要其中包含有初始化列表的构造函数,编译器在编译使用{}语法的构造时会最倾向于调用初始化列表构造函数,哪怕做类型转换也在所不惜,哪怕有类型最佳匹配的普通构造函数或移动构造函数也会被劫持

 

Copy

class Widget { public: Widget(int i, bool b); Widget(int i, double d); Widget(std::initializer_list<long double> il); operator float() const; }; Widget w1(10, true); // 使⽤小括号初始化 //调⽤第⼀个构造函数 Widget w2{10, true}; // 使⽤花括号初始化 // 调⽤第三个构造函数 // (10 和 true 转化为long double) Widget w3(10, 5.0); // 使⽤小括号初始化 // 调⽤第二个构造函数 Widget w4{10, 5.0}; // 使⽤花括号初始化 // 调⽤第三个构造函数 // (10 和 5.0 转化为long double) Widget w5(w4); // 使⽤小括号,调⽤拷⻉构造函数 Widget w6{w4}; // 使⽤花括号,调⽤std::initializer_list构造函数 Widget w7(std::move(w4)); // 使⽤小括号,调⽤移动构造函数 Widget w8{std::move(w4)}; // 使⽤花括号,调⽤std::initializer_list构造函数

编译器这种热衷于把括号初始化与初始化列表构造函数匹配的行为,会导致一些莫名其妙的错误

 

Copy

class Widget { public: Widget(int i, bool b); Widget(int i, double d); Widget(std::initializer_list<bool> il); // element type is now bool … // no implicit conversion funcs }; Widget w{10, 5.0}; //错误!要求变窄转换,int(10)double(5.0)无法转换为bool类型

只有在没有办法把{}中实参的类型转化为初始化列表时,编译器才会回到正常的函数决议流程中

⽐如我们在构造函数中⽤std::initializer_list<std::string>代替std::initializer_list<bool> ,这时⾮std::initializer_list构造函数将再次成为函数决议的候选者,因为没有办法把int和bool转换为std::string:

 

Copy

class Widget { public: Widget(int i, bool b); Widget(int i, double d); Widget(std::initializer_list<std::string> il); … }; Widget w1(10, true); // 使⽤小括号初始化,调⽤第⼀个构造函数 Widget w2{10, true}; // 使⽤花括号初始化,调⽤第⼀个构造函数 Widget w3(10, 5.0); // 使⽤小括号初始化,调⽤第⼆个构造函数 Widget w4{10, 5.0}; // 使⽤花括号初始化,调⽤第⼆个构造函数

{}空初始化列表会发生什么#

假如{}内是空的,类中既有默认构造函数,也有初始化列表构造函数,此时{}会被视为没有实参,而不是一个空的初始化列表,因此会调用默认构造函数。如果就是想调用初始化列表构造函数,这应该使用{{}}的方式

 

Copy

class Widget { public: Widget(); Widget(std::initializer_list<int> il); ... }; Widget w1; // 调⽤默认构造函数 Widget w2{}; // 同上 Widget w3(); // 最令⼈头疼的解析!声明⼀个函数 Widget w4({}); // 调⽤std::initializer_list Widget w5{{}}; // 同上

初始化列表带来的vector的坑#
 

Copy

std::vector<int> v1(10, 20); //使⽤⾮std::initializer_list //构造函数创建⼀个包含10个元素的std::vector //所有的元素的值都是20 std::vector<int> v2{10, 20}; //使⽤std::initializer_list //构造函数创建包含两个元素的std::vector //元素的值为10和20

初始化列表构造函数问题带来的两点启示#
  • 作为类库作者,如果在构造函数中重载了一个或多个初始化列表构造函数,要考虑用户使用{}初始化的情况,最好避免类似std::vector中的情况。应该尽可能做到用户无论用小括号还是花括号进行初始化都不会产生区别。一定要慎重考虑新出现的初始化列表构造函数对其他构造函数的影响!!!
  • 作为类库使用者,必须认真的考虑小括号和花括号之间选择创建对象的方式,最好选择其中一个从一而终。
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一百编程网朱老师

谢谢大爷谢谢大爷谢谢大爷谢谢大

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

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

打赏作者

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

抵扣说明:

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

余额充值