Prefer auto
to explicit type declarations
从 C++11 开始,auto
变量从初始化表达式中推导出类型,这意味着我们必须显式地初始化一个变量。
1 | int x1; //潜在的未初始化的变量 |
而且省去了很多打代码的麻烦。考虑以下两段执行相同操作的代码:
1 | template<typename It> //对从b到e的所有元素使用 |
使用Item2所述的auto
类型推导技术,它甚至能表示一些只有编译器才知道的类型:
1 | // C++11 |
但是,有人觉得不需要使用auto
声明局部变量来保存一个闭包,可以使用std::function
对象。
std::function
是一个C++11标准模板库中的一个模板,它泛化了函数指针的概念。std::function
可以指向任何可调用对象。但创建std::function
对象非常麻烦,而且还可能需要更多内存来存储闭包(堆上)。
1 | std::function<bool(const std::unique_ptr<Widget> &, |
使用auto
除了可以避免未初始化的无效变量,省略冗长的声明类型,直接保存闭包外,还有一个好处是可以避免类型快捷方式有关的问题。
1 | std::vector<int> v; |
v.size()
的标准返回类型是std::vector<int>::size_type
。在Windows 32-bit std::vector<int>::size_type
和unsigned
是一样的大小,但是在Windows 64-bit上std::vector<int>::size_type
是64位,unsigned
是32位,这就会出问题。
还有一个例子,考虑以下代码:
1 | std::unordered_map<std::string, int> m; |
std::unordered_map
的key是const
的,所以std::pair
的类型是std::pair<const std::string, int>
。由于类型不一致,编译器会通过拷贝m
中的对象创建一个临时对象,然后把p
的引用绑定到这个临时对象上。在每个循环迭代结束时,临时对象将会销毁。
使用auto
可以避免这些很难被意识到的类型不匹配的错误:
1 | for(const auto& p : m) |
这样不仅代码更简洁,而且确保与std::unordered_map中真实pair的引用“绑定”, 而并不只是一个临时拷贝的引用。
重点
- auto 声明变量必须初始化, 通常它可以避免一些移植性和效率性的问题, 并可以简化重构, 且比明确指定类型的变量声明打更少的代码。
- auto声明变量会受到Item2和Item2中描述的陷阱的影响。