《Effective Modern C++》学习笔记之条款六:当auto推导的型别不符合要求时,使用带显示型别的初始化

本文介绍了C++中auto自动推导并非万能。以std::vector<bool>为例,使用auto接收其operator[]返回值时,结果并非bool类型,而是代理类类型,使用可能导致未定义行为。但问题并非auto导致,对于存在代理类或隐式转换表达式,可使用带显示型别的初始化或强制类型转换。

虽然auto用起来确实好处多多,到那时也并不是万能的,在有些场景下,我们就不得不使用带显示型别的初始化。例如如下代码:

std::vector<bool> features() {
     std::vector<bool> temp;
     for(int i = 0;i < 10; ++i) {
         temp.push_back(true);
     }
     
     return temp;
}

auto result = features()[5];  //编译通过,但实际将导致未定义行为

bool result2 = features()[5];  //正确

上述代码很简单,一个函数返回一个vector对象,里面放了10个true,然后使用auto接收第6个(从0开始计算)值,我们理所当然的认为,此时result的值为bool类型,但是实际上并不是,std::vector<T>对于bool类型且仅仅对bool类型有特殊处理,其返回值为并不是bool,而是std::vector<bool>::reference类型,它是bool类型的代理类。之所以出现这种结果,是因为STL对std::vector<bool>的operator[]函数做过特殊,用一种压缩的方式表示其持有的bool元素,即每个bool元素用一个比特位来表示。

上述代码中,result2变量被显示声明为bool类型,所以features()[5]将被隐式转换为bool类型,此时并不会有任何问题,但对于使用auto声明的result变量来说,features()[5]的类型为std::vector<bool>::reference,此时result中含有空悬指针,使用它将会导致未定义的行为。

但需要说明的是,上面问题的触发原因并不是auto导致的,所以我们不必舍弃auto语法,相反对于一些存在代理类或者隐试转换表达式,我们应该使用带显示型别的初始化,说直白点就是,如果我们确定表达式返回值,我们可以在赋值前,进行显示强制类型转换。例如上面代码的auto语句,我们可以改成这样:

auto result = static_cast<bool>(features()[5]);

auto sum = static_cast<MyType>(m1 + m2 + m3);

auto index = static_cast<int>(d * c.size());

auto diff = static_cast<float>(1.2);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Chiang木

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

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

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

打赏作者

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

抵扣说明:

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

余额充值