Item5:优先使用 auto,而非显式类型声明
传统显示类型声明存在的问题
1. 忘记初始化产生未知行为
但是,auto声明的变量其类型推导自其初始化表达式,所以它们必须初始化:
1 | int x1; // 有潜在的未初始化风险 |
2. 类型冗长复杂,难以直接写出
在泛型编程、容器操作等场景中,尝尝会出现冗长复杂的类型声明。如:typename std::iterator_traits<It>::value_type,可以直接使用auto代替。
1 | // 传统显式声明:冗长繁琐,易出错 typename |
3. 类型不匹配导致意外的类型转换
std::function是C++11标准库中的一个模板,它把函数指针的思想加以推广。函数指针只能指向函数,而std::function却可以指向任何可调用对象,即任何可以像函数一样实施调用之物。可以处理C++中的闭包类型。
但是,闭包类型只有编译器自己知道,显式声明闭包类型可能产生潜在的类型转换。如:
1 | std::unordered_map<std::string, int> m; |
哈希表中的 std::pair (也就是 std::unordered_map 本身)的类型并不是 std::pair<std::string, int> ,而是 std:: pair<const std::string, int>。
还可以避免一种被称作者为“类型捷径”的问题。如:
1 | std::vector<int> v; |
在 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和6中所描述的毛病。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 肖恩的博客!
评论
