条款5:优先选用auto, 而非显示类型声明
1. auto的功能
- 下面的代码看上去很常见,但有点天真:
int x;
template<typename It> // dwim ("do what I mean")算法,作用范围为[b,e)
void dwim(It b, It e) { while (b != e) {typename std::iterator_traits<It>::value_type currValue = *b;…}
}
// currValue的类型来自类型成员,只有在编译的时候才知道,故而无法直接写出。
得益于C++11 加入的 auto ,这些问题都得以解决:
auto x2; // 错误,需要初始化表达式
auto x3 = 0; // 很好, x的值被正确定义了template<typename It>
void dwim(It b, It e){while(b != e){auto currValue = *b;...}
}
- auto 可以表示那些仅仅被编译器知晓的类型:
auto dereUPLess = // 比较函数[](const std::unique_ptr<Widget>& p1, const std::unique_ptr<Widget>& p2) { return *p1 < *p2}; // std::unique_ptrs
这看上去很cool😎,在 C++14 中,又降温(更cool)了,因为 lambda 表达式的参数可以使用 auto:
// C++14,比较任何类似指针所指向的值
auto derefLess = [](const auto& p1, const auto& p2) { return *p1 < *p2; };
也许你会说:可以使用std::function对象,它可以封装任何可调用对象。声明一个名为 func 的 std::function 对象:
std::function<bool(const std::unique_ptr<Widget> &,const std::unique_ptr<Widget> &)> func;
它可以封装具有以下签名的可调用对象:
//C++11中的函数签名,用于比较std::unique_ptr<Widget>
bool(const std::unique_ptr<Widget> &, const std::unique_ptr<Widget> &)
lambda 返回可调用对象,因此不用auto的C++11 版本的 dereUPLess :
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的使用还可以避免“类型截断”问题:
std::vector<int> v;
...
unsigned sz = v.size();//v.size() 类型是 std::vector<int>::size_type
在32位 Windows 系统上, unsigned 和 size_type 有同样的大小,但是在64位的 Windows 上, unsigned 是32bit的,而 size_type 是64bit的。
auto sz = v.size() // sz的类型为std::vector<int>::size_type
2. auto的不完美
- auto 变量的类型都是从初始化它的表达式推导出来的,可能得不到我们期望的类型(条款2、条款6)。
- 这里我们关注的是:将传统的类型声明替代为 auto 时带来的代码可读性问题。
a. IDE提示对象类型的功能经常能缓解这个问题。
b. 通常并不需要知道对象的准确类型,例如只需要知道一个对象是一个容器、或一个智能指针即可。
3. 要点速记
- auto声明变量时必须初始化,通常不受可移植性或效率问题影响,可以简化重构过程,并且通常比具有显式指定类型的变量需要更少的键盘输入。
- auto 类型的变量也受限于条款2和条款6中描述的陷阱。