05:优先选用auto,而非显式类型推断

  • 优点一:避免变量未初始化
    • 使用auto声明的变量未初始化,直接导致编译报错
  • 优点二:简化变量声明(避免写一长串类型名)
  • 优点三:声明闭包类型(lambda表达式)
    • C++11中lambda式返回值可以使用auto,C++14中lambda式形参也可以使用auto
    • std::function通常比起auto更大更慢,还可能导致内存消耗异常,因此实际使用时更推荐auto
      • 使用auto声明的、存储着一个闭包的变量和该闭包是同一类型,从而它要求的内存量也和该闭包相同
      • 使用std::function声明的、存储着一个闭包的变量是std::function的一个实例,不管给定的签名如何,它都占有固定大小的内存,而这个大小对于其存储的闭包而言并不一定够用,如果是这样,那么std::function的构造函数就会分配堆上的内存来存储该闭包。
  • 优点四:避免类型截断
  • 优点五:避免类型不匹配
    1
    2
    3
    4
    5
    
    std::unordered_map<std::string, int> mp;
    for(auto& item: mp) { 
        // auto=std::pair<const std::string,int>
        // 但是如果显式定义类型,很容易定义为std::pair<std::string, int>&
    }
    

06:当auto推导的类型不符合要求时,使用带显式类型的初始化习惯用法

  • 隐式的代理类型可能导致auto类型推导结果不符合预期,因此应该显式声明类型
  • 代理类:模拟和拓展某些其他类型的行为,比如智能指针,比如std::vector<bool>::reference
    • std::vector<bool>进行了特化,与一般std::vector不同:
      • 一般对于vector<T>operator []操作,返回类型为T&;但是对于vector<bool>operator []操作,返回类型为vector<bool>::reference(因此可能发生到bool的隐式类型转换),这是因为标准库无法返回对bit的引用
      • vector<bool>::reference的实现中,可能有一个指向word的指针和一个对应的offset,很可能出现难以预料的错误
        1
        2
        3
        
        vector<bool> func();
        auto flg = func()[0]; // func()返回一个临时的右值对象,flg是vector<bool>::reference类型,然后临时的右值对象被析构
        // 因为vector<bool>::reference类型中可能有一个指针,再使用flg可能出现未定义的行为
        
    • 表达式模板中,计算结果可能被解析为一棵语法解析树,而非直接返回计算结果,因此实际得到的结果类型(语法解析树)可能并非期望的类型
  • 总之,对(隐形)代理类的auto类型推导往往得到的不是预期的类型,因此要么显式声明类型,要么使用static_cast强转然后进行auto类型推导