auto的优势可不仅仅是让你少打几个类型字符,在有些时候,可以防止手动指定型别带来的错误和性能问题。但这武器也有弊端,在没有IDE的时候,过度auto使用会影响代码的可读性,甚至在极端情况,会有一些意想不到的事情发生。
优势1:auto语句定义变量在无初始化值的时候无法通过编译
int x1; //有潜在的为初始化风险
auto x2; //编译错误!必须要初始化
auto x3 = 0; //没有问题,x的值有合适的定义
优势2:auto表示可以少打几个字,看起来更加简洁
template<typename It>
void dwim(It b, It e)
{while (b != e) {typename std::iterator_traits<It>::value_type currValue = *b;auto currValue = *b; //采用auto的写法...}
}
优势3:闭包的型别类型只能用auto表示
// C++11版本
auto derefUPLess =[](const std::unique_ptr<Widget>& p1,const std::unique_ptr<Widget>& p2){return *p1 < *p2;};
// C++14版本,这个版本可用于任何类似指针之物的比较
auto derefUPLess =[](const auto& p1,const auto& p2){return *p1 < *p2;};
也许有人说,用std::function
可以表示闭包的型别,这个优势有问题,那么对于这一点,细究一下。其实对于下面的写法,还是有区别的:
// auto版本
auto derefUPLess =[](const std::unique_ptr<Widget>& p1,const std::unique_ptr<Widget>& p2){return *p1 < *p2;};
// std::function版本
std::function<bool(const std::unique_ptr<Widget>&,const std::unique_ptr<Widget>&)>derefUPLess = [](const std::unique_ptr<Widget>& p1,const std::unique_ptr<Widget>& p2){return *p1 < *p2;};
撇开function版本的啰嗦不说,性能上同样存在区别。
-
auto
声明的、存储一个闭包的变量,和这个闭包类型相同,所以消耗的存储空间一致。而std::function
声明的、存储一个闭包的变量是std::function
的一个实例,不管给定的签名如何,它都占有固定尺寸的内存。 -
更糟糕的情况是,上述固定尺寸的内存并不一定够用,在不够的情况下,
std::function
构造函数会分配堆上的内存来存储该闭包。 -
再考虑到编译器实现细节会限制内联产生间接函数调用,此时
std::function
开销会变得更大。
综上对比,在闭包声明的时候,auto
是完胜std::function
的。
优势4:避免不小心造成的类型隐身转换
用例子说明:
std::vector<int> v;
...
unsigned sz = v.size();
auto sz = v.size();
上述两种定义中,sz的型别其实是不同的,v.size()
在不同平台下,会产生不同的类型,他的真正型别为std::vector<int>::size_type
。在32位的系统里是第一种写法是一致的,但是64位系统里,则会出现类型缩窄。但使用auto的写法则能避免这样的问题。如果这种区别不足以让你觉得满足,那么看看下面的例子:
std::unordered_map<std::string, int> m;
...for (const std::pair<std::string, int>& p : m)
{... //在p上实施某些操作
}
这段代码看起来合理,但是会有极大隐藏的性能损失,std::unordered_map
的键值部分是const,所以哈希表中的std::pair的型别不是std::pair<std::string, int>
而是std::pair<const std::string, int>
。所以编译器会想办法让类型匹配起来,从而将每一个遍历的对象都复制一遍来满足类型匹配。而这个过程无疑调用了数不清次数的拷贝函数和析构函数。
std::unordered_map<std::string, int> m;
...for (const auto& p : m)
{... //在p上实施某些操作
}
而这样写,一切都没问题了,而且代码也更容易理解了。
劣势 1:auto在某些特殊环境下,推导出来的结果不正常
详见
item2
和item6
劣势 2:auto使用过多会导致代码可读性降低
满篇的
auto
必定让你看不清变量的类型
要点速记 |
---|
1. auto变量必须初始化,基本上对会导致兼容性和效率问题的型别不匹配现象免疫,还可以简化重构流程,通常也比显示指定型别少打一些字。 |
2. auto型别变量都有item2 和 item6 的毛病。 |