优势
防止忘记初始化变量
int x1; // 忘记初始化
auto x2; // error
auto x3 = 0; // correct
防止写过长的显示类型
template<typename It>
void dwim(It b, It e) {
while (b != e) {
typename std::iterator_traits<It>::value_type curr_value = *b;
...
}
}
template<typename It>
void dwim(It b, It e) {
while (b != e) {
auto curr_value = *b;
...
}
}
表示只有编译器才知道的类型
// 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;};
在 C++11 中,使用 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;};
但是,不仅写起来啰嗦,而且因为std::function
和auto
的行为并不相同。auto
持有的类型与lambda
表达是相同,而std::function
对于任意的函数签名均持有一个固定大小的对象。如果这个大小与闭包大小不同,则会申请新的空间。这会浪费内存。而且犹豫标准对于闭包实现的限制,通常来讲auto
对象的运行速度更快。
避免无谓的错用类型
std::vector<int> v;
unsigned sz1 = v.size(); //实际的类型应是 std::vector<int>::size_type
auto sz2 = v.size();
std::unordered_map<std::string, int> m;
for (const std::pair<std::string, int>& p : m) {
...
}
for (const auto & p : m) { // 实际的类型应是 const std::pair<const std::string, int>&
...
}
对于第一种情况,在不同的平台,比如32位和64位平台,可能会有不同的表现,导致难以发现的错误。
对于第二中情况,由于类型的不匹配,导致生成无谓的临时对象,不仅会增加开销,而且对p
取地址还会有不同的行为发生。
推荐使用auto的原因
- 使用的类型更精确
- 使程序更具效率
- 当更改一处类型时,比如函数返回值,不需要去修改其他地方
auto的缺点
auto
从初始化表达式推断类型,但是,初始化表达式的类型有时候并不是我们期待的。这所产生的问题在第二章和第六章阐述。