0. auto关键字
auto
被称作类型说明符,它可以让编译器替我们去分析表达式所述的类型,然后将所定义的变量声明为该类型。
与decltype一样,都属于类型说明符,也是为了解决类型爆炸问题的第二点。
int a = 1, b = 2;
auto c = a + b; // c是int类型
auto
经常用在将表达式的结果赋值给新定义的变量的情况下,因此使用auto定义的变量,一定会有初始值。
关于auto
,需要注意:
- 复合类型与auto
- 常用情况举例
1. 复合类型与auto
1.1 数组
数组的推断结果,会转换成指针:
int arr[] = {1, 2, 3, 4};
auto auto_arr = arr;
cout << sizeof(arr) << endl; // 16
cout << sizeof(auto_arr) << endl; // 8
注意:以上是在我电脑的实验结果,我在《C++ Primer(第5版)》中未看到相关的描述,因此不同编译器不确定结果是什么。以后读到相关文献会来修改,敬请谅解。
1.2 引用
引用的推断结果,会得到不是引用的类型:
int a = 2, &ra = a;
auto b = a; // b是一个整型
因此在使用范围for语句遍历容器时,需要引用类型的,必须明确指出&
:
vector<int> vec = {1, 2, 3, 4, 5};
for (const auto &v : vec) {
// do something
}
1.3 指针
指针的推断结果,依旧是指针:
int a = 2;
int *pa = &a;
auto p = pa; // p是指向int类型的指针
1.4 const限定符
auto
会忽略掉顶层const:
int i = 2;
// ci具有顶层const
const int ci = i;
// b的类型是int
// 可以执行 b = 3;
auto b = ci;
使用指针举例:
int i = 2, j = 4;
// pi具有顶层const
// 不能改变pi的值,即
// 不能执行 pi = &j;
int *const pi = &i;
// p没有顶层const
auto p = pi;
p = &j;
cout << *p << endl; // 4
但是会保留底层const,比如:
const int i = 2, j = 4;
// pi具有底层const
// 不允许 *pi = 5
const int *pi = &i;
// p也具有底层const
auto p = pi;
*p = 5; // ERROR!
对const量取地址,得到的还是底层const,因此:
const int i = 2;
// &i会保留底层const
// pi具有底层const
auto pi = &i;
2. 常用情况举例
auto
虽然好,但是只是对代码编写者好,对于代码阅读者,增加了他阅读代码的负担,因此不推荐频繁使用。
谨记一个原则:让阅读者看着舒服、编写者写的舒服的时候使用。
我们经常在使用迭代器时使用auto
:
vector<int> input = {1, 2, 3, 4, 5};
for (auto it = input.begin(); it != input.end(); ++it) {
// do something
}
// 否则我们要写
// vector<int>::iterator it
还有就是STL各类容器中的size()
函数。它返回的是容器自己的size_type
类型,实际上是一个无符号整型。
很多C++使用者习惯使用int
去获得size()
的结果,但实际上这是不规范的,应该:
string::size_type sz = str.size();
可以使用auto
:
auto sz = str.size();
以上两种情况,都可概括为,某些自定义数据类型为了完善自己的操作,在内部封装了很多基本类型,为了使用该类型、又不清楚该类型具体细节时,可以使用auto
。
3. 总结
auto
被称作类型说明符,它可以让编译器替我们去分析表达式所述的类型,然后将所定义的变量声明为该类型。
使用auto
要注意与复合类型的搭配,①数组会被转换成首元素的指针,②引用会被去掉,③指针会被保留,④顶层const会被去掉,底层const会被保留。