什么是auto?
在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量。
C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
看完长叹一声-----喔!没懂,没关系看下面代码,举个栗子
#include
#include
using namespace std;
int TestAuto()
{
return 10;
}
int main()
{
int a=10;
auto b=a;
auto c='s';
auto d=1.2;
auto e=TestAuto();
cout<<typeid(b).name()<<endl;//这个函数用来打印出变量的数据类型,在这里不多
cout<<typeid(c).name()<<endl;//介绍,以后会详细介绍
cout<<typeid(d).name()<<endl;
cout<<typeid(e).name()<<endl;
system("pause");
return 0;
}
大家会觉得auto 似乎可以自动识别类型,假如是 auto d=1.2 编译器就是识别为:double d= 1.2 ;然后好像就是一种类型声明,但是这里需要注意的是:
使用auto定义变量时必须对其进行初始化
在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。
因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型
(感觉就是:哎!你要定义并初始化一个变量a=10,但是 int 跑了,好吧我 auto 先帮你占个位子,等到编译器处理的时候,我再和 被编译器找回来的的 int 换下位子 。)
1. auto与指针和引用结合起来使用
用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
int main()
{
int x=10;
auto a=&x;
auto* b=&x;
auto& c=x;
cout<<a<<" "<<b<<" "<<c<<endl;
cout<<typeid(a).name()<<endl;
cout<<typeid(b).name()<<endl;
cout<<typeid(c).name()<<endl;
system("pause");
return 0;
}
运行结果:
可以看到,由于前两个都是地址所以他的类型是一个指针,而第三个只是给他取了一个别名,访问的还是用一块地址空间所以类型是int 型
看一段代码:
int main()
{
auto a=10,b=12;
auto c=1.2,d=12;//这里会报一个错
}
这是为什么呢?
当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
1. auto不能作为函数的参数
void TestAuto(auto a)//这里报错
{
//此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
}
2. auto不能直接用来声明数组
(还是第一次见到这个叫顶级数组的,感觉好高级啊,什么顶级高手,顶级武功秘籍啥的,去百度了一下,还没找到,可能是因为我的编译器是vs2012的吧)
3. 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法
4. auto在实际中常见的优势用法就是跟以后会讲到的C++11提供的新式for循环,还有lambda表达式等进 行配合使用。
5. auto不能定义类的非静态成员变量(暂不做讲解,后面讲)
6. 实例化模板时不能使用auto作为模板参数(暂不做讲解,后面讲)
先看一段代码:
int main()
{
int arr[10]={0,1,2,3,4,5,6,7,8,9};
int len=sizeof(arr)/sizeof(arr[0]);
int i=0;
for(i=0; i<len; i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
for(auto a : arr)//范围for
{
cout<<a<<" ";
}
cout<<endl;
system("pause");
return 0;
}
第一种是我们熟悉的for循环,通过控制数组下标和解引用来访问数组里的元素。
第二种是我们的范围for,并结合了我们刚学的auto关键字,那这个是怎么实现的呢?
先看下范围for的定义:
1.定义:
对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引 入了基于范围的for循环。
for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二 部分则表示被迭代的范围
数组 arr 并把数组的内容依次付给 a 然后完成打印,不需要知道数组的大小,交给编译器处理,整个过程是自动识别的,因此十分方便。
注意:范围for与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。
2.范围for的使用条件
我们都知道,以前在c语言的时候,我们表示空的时候都是用NULL来表示的。但是在C++中以后就需要使用nullptr 了,这是为什么呢?
看一段代码:
#include
#include
using namespace std;
void f(int)
{
cout<<"f(int)"<<endl;
}
void f(int*)
{
cout<<"f(int*)"<<endl;
}
int main()
{
f(0);
f(NULL);
f((int*)NULL);
f(nullptr);
system("pause");
return 0;
}
运行结果:
这是为什么?因为NULL在头文件里被宏定义为了0 ,而NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。以后在使用时可能会出现歧义。
为了考虑兼容性,C++11并没有消除常量0的二义性,C++11给出了全新的nullptr表示空值指针。
C++11为什么 不在NULL的基础上进行扩展,这是因为NULL以前就是一个宏,而且不同的编译器厂商对于NULL的实现可能不太相同,而且直接扩展NULL,可能会影响以前旧的程序。
因此:为了避免混淆,C++11提供了nullptr, 即:nullptr代表一个指针空值常量。nullptr是有类型的,其类型为nullptr_t,仅仅可以被隐式转化为指针类 型,nullptr_t被定义在头文件中:
typedef decltype(nullptr) nullptr_t;
注意:
1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
2. 在C++11中,sizeof(nullptr) 与 sizeof((void)0)所占的字节数相同。
3. 为了提高代码的健壮性,在后续表示指针空值时建议好使用nullptr