C++中auto的优点和使用注意

一个逗逗 2019-12-15

一、优点

(一)避免忘记初始化

写C++时忘记初始化常常会导致难以发现的bug,而使用auto则可以避免这一风险,因为像auto x;这样的语句编译器是不会通过的——连初始化都没有,编译器没办法推导出x的类型。

(二)避坑

有时会忘记正在使用的数据结构包含的类型到底是什么,使得我们预期的类型和实际类型不一样。举个栗子,如果你对效率有很高的追求,那么下面这样的代码不能达到令你满意的效果:

unordered_map<int, int> m ({ {1,1}, {2,2} });
do_sth (const pair<int, int>& p);//将m的元素作为实参

这段代码本意是想通过传引用传参避免复制、提高效率,但其实这段代码运行时还是将实参复制了一遍。因为unordered_map的元素为pair<const key, value>类型,所以编译器要先对pair<const key, value>类型的值进行复制操作,产生一个pair<key, value>类型的临时变量,再将p与这个临时变量进行绑定。而如果把上述代码中的函数签名改为const auto& p,那么就可以直接进行绑定了。
为了验证上面这段描述的正确性,我们用代码验证如下:

unordered_map<int, int> m ({ {1,1}, {2,2} });//unordered_map的元素为pair<const key, value>类型
//对auto_p取址会得到*m.begin()的地址
const auto& auto_p = *m.begin();
//若上面的描述正确,那么对p取址会得到临时变量的地址,它与auto_p的取址结果不同
const pair<int, int>& p = *m.begin();
//将取址结果转化为int储存起来
int p_address = (int)&p, auto_p_address = (int)&auto_p;

if (p_address == auot_p_address)
    cout << "t";
else
    cout << "f";

输出为f,说明上面的描述正确。
避坑的另一方法就是查看文档源代码

(三)使重构简单

如果有一天需要把int x改为long long x,只需要更改值就可以了。

二、使用注意

(一)型别推导通常忽略引用

关于型别推导的内容看。例如,用auto作为函数返回类型时,即使return arr[i],返回值也不是引用。

(二)隐形代理类

例如,vector<bool>::operator []返回的是vector<bool>::reference型别的对象(vector中嵌套的一个类)。再例如,一些C++库中的类采用了表达式模板。此时使用auto就会导致得到的类型和我们预期的不一样。

解决方法是:1.查看文档或源代码来弄清楚是否有代理类的存在。2.使用static_cast进行类型转换以确保得到的类型是我们想要的。

相关推荐