有时候,你想往东,auto
类型推导的结果偏偏往西。考虑如下代码:
std::vector<bool> features(cosnt Widget& w);
Widget w;
bool highPriority = features(w)[5];
processWidget(w, hightPrioirty);
上述代码没有什么问题,如果我们吧highPriority
从显示类型改为auto
呢?
auto highPriority = featrues(w)[5];
所有代码仍然可编译,但是其行为则变得不再可以预测了
processWidget(w, hightPrioirty); //未定义行为
上述函数调用中,highPriority
的类型不再是bool
了。它返回的是std::vector<bool>::reference
类型的对象。之所以要弄出个std::vector<bool>::reference
,是因为std::vector<bool>
做过特化,用了一种压缩形式表示其持有bool
元素,每个bool
元素用一个比特来表示。这种做法给std::vector<T>
的operator[]
带来一个问题,因为按说std::vector<T>
的operator[]
应该返回T&
,然而C++中给你却禁止比特的引用。、
auto highPriority = featrues(w)[5];
对features
的调用会返回一个std::vector<bool>
类型的临时对象temp
,针对temp
执行operator[]
,返回一个std::vector<bool>::reference
类型对象,该对象含有一个指涉及到机器字的指针,该机器字在一个持有temp
所管理的那样比特币的数据结构中,还要加上第5个比特所对应的机器字的偏移量。由于highPriority
是std::vector<bool>::reference
对象的一个副本,所以highPriority
也含有一个指涉到temp
中的机器字的指针,加上还要在第5个比特所对应的机器字的偏移量。在表达式结束处,temp
会被析构,因为它是一个临时对象。结果,highPriority
会含有一个空悬指针,最终导致processWidget
时出现未定义行为。
std::vector<bool>::reference
是一个代理类的实例。所谓代理类,就是为了模拟或增广其他类型的类;所以我们要防止写出以下这样的代码
auto someVar = "隐形"代理类型表达式
auto highPriority = static_cast<bool>featrues(w)[5]; //是一种安全做法