优先使用auto

测试环境


vs2015

C++11

win10 64位

auto的优点


  1. auto 变量从它初始化推导出其类型,所以它们必须被初始化,规避了忘初始化的风险。对于声明一个变量int nTmp;也许忘了初始化,编译通过,使用时也许是0也许不是,而使用auto nTmp = 10;必须初始化,否则编译不通过

  2. 一个使用 auto 声明持有一个封装的变量和封装体有同样的类型,也仅使用和封装体同样大小的内存。持有一个封装体的被 std::function 声明的变量的类型是 std::function 模板的一个实例,并且对任何类型只有一个固定的大小。这个内存大小可能不能满足封装体的需 求。出现这种情况时, std::function 将会开辟堆空间来存储这个封装体。导致的结果就是 std::function 对象一般会比 auto 声明的对象使用更多的内存。 通过 std::function 对象来调用一个封装体比通过 auto 对象要慢,同时也有可能抛出内存不足的异常

    例如:

     std::function<void(int,int)> varFun1 = [](int x,int y){cout<< x <<y<<endl;}
     auto varFun2 = [](int x,int y){cout<< x <<y<<endl;}
    
  3. 可以避免错误的声明类型

    例如:

     std::vector<int> vec;
     unsigned int nSize = vec.size();
    
     std::unordered_map<std::string, int> unorderedMap;
     for (const std::pair<std::string, int>& one : unorderedMap)
     {
     }
    

    上述例子我们可能写过,对于vec.size()的返回类型是std::vector<int>::size_type,最终找到size_type的定义(注意我的环境)如下:

     #ifdef _WIN64
         typedef unsigned __int64 size_t;
     #else
         typedef unsigned int     size_t;
    

    所以这段代码unsigned int nSize = vec.size();在32位机器上没什么问题,在64位机器上可能结果就不正确了,如果我们使用auto就可以避免这样的问题

    再如上面的例子中

     for (const std::pair<std::string, int>& one : unorderedMap)
    

    在哈希表中的 std::pair 的类型不是 std::pair<std::string, int> ,而是 std::pair<const std::sting, int> 。但是这不是循环体外变量 p 的声明类型。后果就是,编译器竭尽全力去找到一种方式,把 std::pair<const std::string, int> 对象(正是哈希表中的内容)转化为 std::pair<std::string, int> 对象( p 的声明类型)。这个过程将通过复制 m 的一个元素到一个临时对象,然后将这个临时对象和 p 绑定完成。在每个循环结束的时 候这个临时对象将被销毁。本来想简单地将引用 p 和 m 的每个元素绑定的。 这种无意的类型不匹配可以通过 auto 解决for (const auto& one : unorderedMap)。 上面的例子说明显式指定的类型有可能导致隐式的转换。如果你使用 auto 作为目标变量的类型,你不必为你声明类型和用来初始化它的表达式类型之间的不匹配而担心

当auto推导出非预期类型时应当使用显式的类型初始化


上面列出了使用auto的优点,有时auto并不能推导出我们想要类型,例如:

std::vector<bool> features(const CWidget& objWidget);

CWidget objWidget;

auto bPriority = feature(objWidget)[5];

// 发生未定义行为
procWidgetByPriority(objWidget,bPriority);

先声明: 对于其他所有形参型别而言,std::vector::operator[]都返回T&,只有当形参型别是bool时是个例外,它返回的是个std::vector::reference

按照这个声明那么bPriority的类型就是std::vector::reference,当调用函数procWidgetByPriority时产生未定义行为,至于原因取决于std::vector::reference其内部的实现, std::vector::reference内部有个指针,指向一个机器字,该机器字持有那个被引用的比特,feature(objWidget)返回的是个临时变量,当调用函数procWidgetByPriority时继续使用其内部指针, 导致产生未定义行为,而修改成如下代码:

bool bPriority = feature(objWidget)[5];

按照这样修改,就会发生std::vector::reference向bool型别的隐式转换,所以当使用auto时发生未期望型别时,可以使用类型转换,例如修改如下:

auto bPriority = static_cast<bool>(feature(objWidget)[5]);

同时在使用auto并且想发生型别转换时也可以使用类型转换:

double calcVal();
auto fVal = static_cast<float>(calcVal());

这种带显示型别的初始化物可以强制auto推导出我们期望的型别