《Effective Modern C++》学习总结(条款6- 10)

本文总结了《Effective Modern C++》中条款6至10的关键点,包括:使用显式类型初始化避免auto推导错误、区分与的区别、优先使用而非或、使用别名而不是typedef、以及作用域限定枚举的优点。文章深入探讨了C++11及后续版本的特性,强调了在C++编程中的一些最佳实践。
摘要由CSDN通过智能技术生成

条款6:当auto推导出非预期类型时应当使用显式的类型初始化

1.一种特殊情况:auto在推导vector<bool>时会返回vector<bool> reference
  • 常识是:std::vector<T>operator[]常常返回一个T&
std::vector<bool> features();
auto ret = features();                	 		//返回vector<bool> reference
bool ret2 = features();                			//返回bool(通过隐式转换)
auto ret3 = static_cast<bool>(features);    	//返回bool(通过static_cast强制casting)
  • vector<bool>operator[]的返回值其实并不是bool类型,vector<bool>比较特殊,它返回的是vector<bool>::reference,为什么要这样呢?返回一个bool引用类型不就完了嘛,标准库干嘛非要这么大费周章的搞了个这样的类型呢?,原因有以下几个:

    • 因为bool占用一个字节,标准库为了节省内存,改用bit来表示;
    • 因为operator[]需要返回一个内部元素的引用,但是没办法对一个bit进行引用;
    • 为了让返回的类型统一,无论是bool类型,还是其它类型;
  • 为此标准库为了实现上述三个目标就封装了一个内部的类型vector<bool>::reference,是一个proxy代理类,具体参见cppreference因此auto在这里老老实实得到了一个vector<bool>::reference类型。

  • 我们可以通过使用static_cast强制进行类型转换得到我们想要的类型,以避免上述问题

2.个人思考
  • 如果我都使用强制转换类型了,那还有什么必要使用auto呢?使用auto的目的本来就是想要让编译器帮助我们进行类型推断,以减少重复的类型名使用,那么这样做的意义在哪? 仅仅是为了解决在使用auto时出现的问题吗?个人的一个思路是——auto常常用于泛型编程中实现自动推断类型,这样在整个模板在有一处发生变动时由于有auto的存在可以不用改动太多地方就能继续适用。同时,对于一些基础的内置类型,也可以使用auto(基本不会犯错)。
3.请记住:
  • 对于一些看不见的proxy类型,使用auto对这类初始化表达式进行类型推导会推导出错误的类型。
  • 通过显示的类型初始化惯用法可以强制auto推导出目标类型。

 

第三章:使用Modern C++(C++ 2.0及以上)

 

条款7:在创建对象时区分(){}

1.一般来说,值得初始化有如下三种方式:
int x(0);           			// initializer is in parentheses
int y = 0;						// initializer follows "="
int z{
   0};						// initializer is in braces
int c = {
   0};					// initializer uses "=" and braces
std::vector<int> v1(10,20); 	//使用的是非初始化列表的版本,10个元素,每个元素的值是20
std::vector<int> v2{
   10,20}; 	//使用的带初始化列表的版本,2个元素,值分别是10,20
2.等号往往是最容易误导人判断的符号,必须区分赋值与初始化的关系
Widget w1(2);   				//调用的默认构造函数
Widget w2 = w1; 				//调用的是拷贝构造函数
w1 = w2;        				//调用的赋值操作符
3.特例:在C++11中引入的std::atomic是一个不可拷贝的对象,对于它的初始化是不能利用 y = 0这种形式的,因为它会调用默认拷贝构造函数。
std::atomic<int> ail{
   0};		//fine
std::atomic<int> ai3 = 0;   	//error
  • 因此我们得到结论:y = 0x(0) 这两种形式都有其不适用的地方,而z{0}这种形式则都可以适用,这也就是为什么在C++11中这种初始化方式被称为统一初始化的原因。除此之外统一初始化的这种方式还可以避免窄化的转换和复杂的语法分析。
4.(){}二者最大的区别是:{}这种初始化方式调用的是带有initializer_list的构造函数
class Widget {
   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值