C++中auto的优点和使用注意
一、优点
(一)避免忘记初始化
写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进行类型转换以确保得到的类型是我们想要的。