10.1.1 关键字C+11新增了很多关键字,这些关键字都各有不同的用途,有的关键字功能很复杂,可以用在编程的各个方面。通过使用有特殊功能的关键字,可以极大的缩减代码量。10.1.1 关键字1.auto在C+11标准之前,auto关键字已经存在,其作用是限定变量的作用域。在 C+11标准中,auto被赋予了新的功能,使用它可以让编译器自动推导出变量的类型。auto x=10;/变量x为int类型 10.1.1 关键字在上述代码中,使用auto定义了变量x,并为其赋值为10,则变量x的类型由它的初始化值决定。由于编译器根据初始化值推导并确定变量的类型,因此auto修饰的变量必须初始化。10.1.1 关键字除了修饰变量,auto还可以作为函数的返回值。auto func()/.功能代码return 1;10.1.1 关键字虽然auto可以作为函数的返回值,但是auto不能修饰函数参数。除了修饰变量、函数返回值等,auto最大的用途就是用于模板编程中,简化代码。mapstring,vector m;for(auto value=m.begin();value!=m.end();value+)/10.1.1 关键字如果不使用auto,则代码如下所示:mapstring,vector m;mapstring,vector:iterator value;for(value=m.begin();value!=m.end();value+)/10.1.1 关键字此外,在模板编程中,变量的类型依赖于模板参数,有时很难确定变量的类型。当不确定变量类型时,可以使用auto解决。template void multiply(T1 x,T2 y)auto result=x*y;/使用auto修饰变量result 10.1.1 关键字2.decltypedecltype关键字是C+11标准新增的关键字,其功能与auto关键字类似,也是在编译时期进行类型推导,但其用法与auto不同,decltype关键字的使用格式如下所示:decltype(表达式)在上述格式中,decltype关键字会根据表达式的结果推导出数据类型,但它并不会真正计算出表达式的值。需要注意的是,decltype关键字的参数表达式不能是具体的数据类型。10.1.1 关键字int a;int b;float f;cout typeid(decltype(a+b).name()endl;/推导结果:intcout typeid(decltype(a+f).name()endl;/推导结果:floatcout typeid(decltype(int).name()decltype()放在函数后面用于推导函数返回值类型。示例代码如下:templateauto multiply(T1 x,T2 y)-decltype(x*y)在泛型编程中,这种方式称为追踪返回类型,也称尾推导。有了-decltype(),程序设计者在编写代码时就无需关心任何时段的类型选择,编译器会进行合理的推导。10.1.1 关键字3.nullptr在C语言中,为避免野指针的出现,通常使用NULL为指针赋值。C语言中NULL的定义如下:#define NULL(void*)0)由上述定义可知,NULL是一个void*类型的指针,其值为0。在使用NULL给其他指针赋值时,发生了隐式类型转换,即将void*类型指针转换为了要赋值的指针类型。10.1.1 关键字NULL的值被定义为字面常量0,这样会导致指针在使用过程中产生一些不可避免的错误。例如,有两个函数,函数声明如下:void func(int a,int*p);void func(int a,int b);在上述代码中,函数func()是重载函数,如果在调用func()函数时,传入第二个参数为0或NULL,则编译器总会调用第二个func()函数,即两个参数都是int类型的函数。这就与实际想要调用的函数相违背了。10.1.1 关键字如果想要根据传入的参数,成功调用相应的func()函数,则需要使用static_cast转换运算符将0强制转换,示例代码如下:func(1,0);/调用func(int a,int b)func(1,static_cast(0);/调用func(int a,int*p)虽然使用static_cast转换运算符解决了问题,但是这种方式极易出错,而且也会增加代码的复杂程度。10.1.1 关键字为了修复上述缺陷,C+11标准引入了一个新的关键字nullptr,nullptr也可以为指针赋值,避免出现野指针。但是,nullptr是一个有类型的空指针常量,当使用nullptr给指针赋值时,它可以隐式转换为等号左侧的指针类型。10.1.1 关键字nullptr只能被转换为其他指针类型,不能转换为非指针类型。示例代码如下:int*p=nullptr;/正确int x=nullptr;/错误,nullptr不能转换为int类型注 意 10.1.1 关键字由于nullptr只能转换为其他指针类型,因此它能够消除字面常量0带来的二义性。在调用func()函数时,如果传入nullptr作为第二个参数,则func()函数能够被正确调用。func(1,0);/调用func(int a,int b)func(1,nullptr);/调用func(int a,int*p)10.1.1 关键字4.=default与=delete构造函数、析构函数、拷贝构造函数等是类的特殊成员函数,如果在类中没有显式定义这些成员函数,编译器会提供默认的构造函数、析构函数、拷贝构造函数等。但是,如果在类中显式定义了这些函数,编译器将不会再提供默认的版本。10.1.1 关键字如果在程序中需要调用无参的构造函数,就需要程序设计者自己定义一个无参的构造函数,即使这个无参的构造函数体为空,并没有实现任何功能。在实际开发中,一个项目工程中的类非常多,这样做势必会增加代码量。10.1.1 关键字为了使代码更简洁高效,C+11标准引入了一个新特性,在默认函数声明后面添加“=default”,显式的指示编译器生成该函数的默认版本。class Animalpublic:Animal()=default;Animal(string name);private:string _name;10.1.1 关键字有时,不希望类的某些成员函数在类外被调用,例如,在类外禁止调用类的拷贝构造函数。在C+98标准中,通常的做法是显式声明类的拷贝构造函数,并将其声明为类的私有成员。而C+11标准提供了一种更简便的方法,在函数的声明后面加上“=delete”,编译器就会禁止函数在类外调用,这样的函数称为已删除函数。10.1.1 关键字class Animalpublic:/./在类外禁止调用拷贝构造函数Animal(const Animal&)=delete;10.1.1 关键字除了修饰类的成员函数,“=delete”还可以修饰普通函数,被“=delete”修饰的普通函数,在程序中也被禁止调用。示例代码如下:void func(char ch)=delete;func(a);/错误在上述代码中,func()函数被“=delete”修饰,当传入字符a调用func()函数时,编译器就会报错,提示“func()函数是已删除函数”。10.1.2 基于范围的for循环在传统C+中,使用for循环遍历一组数据时,必须要明确指定for循环的遍历范围,但是,很多时候,对于一个有范围的集合,明确指定遍历范围是多余的,而且容易出现错误。针对这个问题,C+11标准提出了基于范围的for循环,该for循环语句可以自动确定遍历范围。10.1.2 基于范围的for循环基于范围的for循环格式如下:for(变量:对象)/在上述语法格式中,for循环语句在遍历时,会遍历对象,将取到的值赋给变量,执行完循环体中的操作之后,再自动取对象中的下一个值赋给变量,直到对象中的数据被迭代完毕。10.1.2 基于范围的for循环vector v=1,2,3,4,5,6;for(auto i:v)cout i 返回值类型 函数体 在上述格式中,参数列表、返回值类型、函数体的含义都与普通函数相同。如果lambda表达式不需要参数,并且函数没有返回值,则可以将()、-和返回值类型一起省略。捕获列表是lambda表达式的标识,编译器根据判断接下来的代码是否是lambda表达式。捕获列表能够捕获lambda表达式上下文中的变量以供lambda表达式使用。10.1.3 lambda表达式根据捕获规则,捕获列表有以下几种常用的捕获形式:(1):空捕获,表示lambda表达式不捕获任何变量。(2)var:变量捕获,表示捕获局部变量var。如果捕获多个变量,变量之间用“,”分隔。(3)&var:引用捕获,表示以引用方式捕获局部变量var。(4)=:隐式捕获,表示捕获所有的局部变量。(5)&:隐式引用捕获,表示以引用方式捕获所有的局部变量。10.1.3 lambda表达式/例10-1 lambda.cppint main()int num=100;auto f=num(int x)-int return x+num;/lambda表达式cout f(10)endl;vector v=54,148,3,848,2,89;/创建vector对象v/调用for_each()函数遍历输出v容器中的元素for_each(v.begin(),v.end(),(auto n)cout n ;);return 0;10.1.3 lambda表达式上述代码首先定义了一个lambda表达式,该lambda表达式有一个int类型的参数x,返回值为int类型,并以值传递的方式捕获局部变量num;在函数体内部返回x与num的相加之和。将lambda表达式赋值给变量f,通过f调用lambda表达式,调用方式与普通函数类似。然后创建了vector对象v,并调用for_each()函数遍历对象v,输出其中的元素。for_each()函数的第三个参数是一个lambda表达式,该lambda表达式不捕获任何变量,它有一个int类型的参数n(对象v中的元素),在函数体中输出n的值。10.2 智能指针在C+编程中,如果使用new手动申请了内存,则必须要使用delete手动释放,否则会造成内存泄露。对内存管理来说,手动释放内存并不是一个好的解决方案,C+98中提出了智能指针auto_ptr解决了内存的自动释放,但是auto_ptr有诸多缺点,例如,不能调用delete,并且,如果auto_ptr出现错误,只能在运行时检测而无法在编译时检测。10.2 智能指针为此,C+11标准提出了三个新的智能指针:unique_ptr、shared_ptr和weak_ptr。unique_ptr、shared_ptr和weak_ptr是C+11标准提供的模板类,用于管理new申请的堆内存空间。这些模板类定义了一个以堆内存空间(new申请的)指针为参数的构造函数,在创建智能指针对象时,将new返回的指针作为参数。同样,这些模板类也定义了析构函数,在析构函数中调用delete释放new申请的内存。当智能指针对象生命周期结束时,系统调用析构函数释放new申请的内存空间。10.2.1 unique_ptrunique_ptr主要用来代替C+98标准中的auto_ptr,它的使用方法与auto_ptr相同,其语法格式如下:unique_ptr 智能指针对象名称(指针);在上述格式中,unique_ptr是模板类型,后面是智能指针对象名称,其命名遵守标识符命名规范。智能指针对象后面的小括号中的参数是一个指针,该指针是new运算符申请堆内存空间返回的指针。10.2.1 unique_ptrunique_ptr pi(new int(10);class A;unique_ptr pA(new A);10.2.1 unique_ptr在上述代码中,第一行代码创建了一