传统显示类型声明存在的问题
1. 忘记初始化产生未知行为
但是,auto声明的变量其类型推导自其初始化表达式,所以它们必须初始化:
c++
int x1; // 有潜在的未初始化风险
auto x2; // 编译错误!必须有初始化表达式
auto x3 = 0; // 没问题, x 已经定义了
2. 类型冗长复杂,难以直接写出
在泛型编程、容器操作等场景中,尝尝会出现冗长复杂的类型声明。如:typename std::iterator_traits<It>::value_type,可以直接使用auto代替。
c++
// 传统显式声明:冗长繁琐,易出错 typename
std::vector<int>::const_iterator it1 = vec.cbegin();
// auto 声明:简洁高效,无需记忆复杂类型
auto it2 = vec.cbegin();
3. 类型不匹配导致意外的类型转换。
std::function是C++11标准库中的一个模板,它把函数指针的思想加以推广。函数指针只能指向函数,而std::function却可以指向任何可调用对象,即任何可以像函数一样实施调用之物。可以处理C++中的闭包类型。
但是,闭包类型只有编译器自己知道,显式声明闭包类型可能产生潜在的类型转换。如:
c++
std::unordered_map<std::string, int> m;
// 看似合理,实则存在类型不匹配
for (const std::pair<std::string, int>& p: m) {
... // 在p上实施某些操作
}
哈希表中的 std::pair (也就是 std::unordered_map 本身)的类型并不是 std::pair<std::string, int> ,而是 std:: pair<const std::string, int>。
还可以避免一种被称作者为"类型捷径"的问题。如:
c++
std::vector<int> v;
unsigned sz = v.size();
在 32 位 Windows 上, unsigned 和 std:: vector<int>::size_type 的尺寸是一样的,但在 64 位 Windows 上, unsigned 是 32 位,而 std:: vector<int>::size_type 则是 64 位。
其他优势
auto存储所需的内存可能比std::function更小,且调用效率更高(std::function采用类型擦除技术,存在间接调用开销,auto直接推导闭包原始类型,无额外损耗)。- 方便进行统一修改和重构,变量类型会随初始化表达式自动适配,修改源头类型时,无需手动调整所有相关变量,减少遗漏风险。
- 支持匿名类型的直接使用,C++中的
lambda表达式、匿名类均为编译器生成的匿名类型,无法手动显式声明,auto是唯一能直接存储这类对象的方式。
可能存在的问题:无法一眼看出对象的类型,但是IDE的对象类型显示能力能缓和这个问题,而且良好的命名比类型更能表达意图。
总结
auto变量必须初始化,基本上对会导致兼容性和效率问题的类型不匹配现象免疫,还可以简化重构流程,通常也比显式指定类型要少打一些字。auto类型的变量都有着2. 理解 auto 类型推导和6中所描述的毛病。