引子
C++中一些与类型声明相关的几个问题:
- 显示声明了一个变量,但是没有初始化,变量是一个不确定的值;
- 模板中对依赖类型的声明很麻烦;
- 无法显式声明闭包的类型;
- ...
这些问题都可以使用auto解决!
正文
1. 避免未初始化的变量
int x1; // potentially uninitialized
auto x2; // error! initializer required
auto x3 = 0; // fine, x's value is well-defined
2. 避免冗余的变量声明
第一段代码可以看到我们需要使用迭代器类型萃取得到实际对象类型,而第二段使用auto可以推导出对象类型。
template<typename It> // algorithm to dwim ("do what I mean")
void dwim(It b, It e) // for all elements in range from
{ // b to e
while (b != e) {
typename std::iterator_traits<It>::value_type
currValue = *b;
template<typename It> // as before
void dwim(It b, It e)
{
while (b != e) {
auto currValue = *b;
…
}
}
3. 获取闭包类型
由于auto可以进行类型推导(Item 2),因此可以推导出仅有编译器才知道的类型。
auto derefUPLess = // comparison func.
[](const std::unique_ptr<Widget>& p1, // for Widgets
const std::unique_ptr<Widget>& p2) // pointed to by
{ return *p1 < *p2; }; // std::unique_ptrs
在C++14中,lambda表达式中也可以使用auto
auto derefLess = // C++14 comparison
[](const auto& p1, // function for
const auto& p2) // values pointed
{ return *p1 < *p2; }; // to by anything
// pointer-like
lambda表达式和std::function对比
- 什么是std::function
std::function是C++11标准库中的一个类模板,用来绑定任意的可调用对象(函数、函数指针、lambda、重载了调用运算符的类对象...) - auto声明的对象优点
占用更小的内存
调用速度更快
声明方式更简单
4. 避免类型截断
std::vector<int> v;
…
unsigned sz = v.size();
一般来说,std::vector<int>::size_type指定为一个无符号整数类型。在某些操作系统中,unsigned int和std::vector<int>::size_type类型不一致,会导致意想不到的问题,此时如果用auto sz = v.size();就可以避免。
5. 避免类型不匹配导致的效率下降
显式声明类型与实际类型不一致时,会导致隐式类型转换。
std::unordered_map<std::string, int> m;
…
for (const std::pair<std::string, int>& p : m)
{
… // do something with p
}
我们常会用到这种写法去遍历容器,值得注意的是unordered_map的key是const的,即hash map中std::pair的类型是std::pair<const std::string, int>,如果我们写成上述代码的样子,就会产生一个临时变量用于拷贝,循环结束后,临时变量再被销毁。因此最好使用下面这种形式。
std::unordered_map<std::string, int> m;
…
for (const auto& p : m)
{
… // do something with p
}
这种情况下,如果使用p的地址也可以保证是指向m中元素的地址而不是一个临时变量的地址。
网友评论