[Effective Modern C++] Item 6. Use the explicitly typed initializer idiom when auto deduces undesired types - 当推断意外类型时使用显式的类型初始化语句

时间:2024-01-02 20:32:49

条款6 当推断意外类型时使用显式的类型初始化语句

基础知识

  当使用std::vector<bool>的时候,类型推断会出现问题:

std::vector<bool> features(const Widget& w);
// OK
bool highPriority = features(w)[];
processWidget(w, highPriority);
// ERROR
auto highPriority = features(w)[];
processWidget(w, highPriority); // undefined behavior

  std::vector<bool>的operator[]操作并不返回一个bool类型,而是返回一个std::vector<bool>::reference(一个std::vector<bool>的内嵌类)。

  存在以上类型是因为std::vector<bool>返回紧凑形式的bool,每一位表示一个bool。vector的operator[]操作返回T&,但是C++静止引用为bit的形式。所以std::vector<bool>的operator[]操作返回一个类似bool&的对象std::vector<bool>::reference,并且隐式转换为bool。

  在使用auto时候,返回可能为一个指针以及偏移量,但随后指向出的内存会被释放,所以highPriority会变成一个悬垂指针(dangling pointer)。

  一些代理类十分明显,如std::shared_ptr和std::unique_ptr,有一些不明显如std::vector<bool>和std::bitset。

  C++中的有些库使用了一种叫做表达式模板(expression template)的技术来提高算术运算的效率。如Matrix + Matrix 返回一个代理类Sum<Matrix, Matrix>。

  在源代码中很难隐藏,所以可以通过以下方式识别代理:

namespace std {
template<class Allocator>
class vector<bool, Allocator> {
public:
class reference {};
reference operator[](size_type n);
};
} // 返回了reference类型

  可以使用显式类型初始化语句(explicitly typed initializer idiom)方式使用auto:

auto highPriority = static_cast<bool>(features(w)[]);

总结

  • “不可见”的代理类型会导致auto推断初始化表达式时出现错误的类型
  • 显式类型初始化语句强制auto推断为你想要的类型