Item 1:优先选用auto,而非显式类型声明
在C++11中,使用auto关键字可以将程序员从输入繁琐的类型中解放出来。
Example: //简化前的代码 void loopover(std::vector<std::string> &vs) { for (std::vector<std::string>::iterator i = vs.begin(); i < vs.end(); i++) { //code } } //简化后的代码 void loopover(std::vector<std::string> &vs) { for (auto i = vs.begin(); i < vs.end(); i++) { //code } }
上例中,auto能够自动推导出vs.begin()的类型,从而避免了冗长的类型说明,该用法是值得大力推荐的。
Item 2:当auto推导出的类型不符合要求时,使用带显式类型的初始化物习惯用法
一个普遍的规律是,“隐形”代理类和auto不能够和平共处,倘若直接连用会导致未定义行为。 Example: std::vector<bool> features(const Widget& w); Widget w; ... bool highPriority = features(w)[5];//假设第5个bit表示Widget是否有高优先级 ... processWidget(w,highPriority); 上述代码没有什么问题,若将highPriority的显式的类型换作auto: auto highPriority = features(w)[5]; 所有代码仍可编译,但其行为变得不可预测。 这里std::vector::operator[]对其他形参类别而言都返回容器中元素的引用,单单bool是个例外,它返回的是std::vector<bool>::reference类别的对象,
属于“隐式”代理类型。auto与其直接连用会导致未定义行为。 因此要防止这样的代码: auto someVar = "隐形"代理类别表达式 在这种情况下,不要放弃auto,而是选择进行一次强制类型转换。 如上例可改为: auto highPriority = static_cast<bool>(features(w)[5]); 这样既保证了正确性,又不必放弃auto所具有的好处。
所谓代理类,是为了模拟或增广其他类型的类。其用途广泛,比如vector<bool>::reference就是为了制造vector<bool>的operator[]返回了一个bit的引用假象。再比如,标准库中的智能指针也是代理类,它们是为了将资源管理嫁接到裸指针之上。
同样属于代理类阵营的,还有一些C++库中的类,它们采用了表达式模板的技术,这些库最开始是为了提高数值运算的效率。
举一个例子,提供一个 Matrix 类和 Matrix 对象 m1, m2, m3和m4 ,下面的表达式:
Matrix sum = m1 + m2 + m3 + m4;
如果Matrix对象的operator+返回的是结果的代理,而非结果本身,则上述表达式的计算会高效得多。(这样不必每步都进行计算,而是先存着,等到用到计算得时候再去计算)。所以,两个Matrix对象的operator+会返回一个代理类对象,比如Sum<Matrix,Matrix>,而不是一个Matrix对象。