成都专业做游戏网站,校园网站建设 德育,企业网站能提供哪些服务,成都网站设计优选柚v米科技第七章 为改变思考方式而改变
7.1 指针空值--nullptr
7.1.1 指针空值#xff1a;从0到NULL#xff0c;再到nullptr
传统C头文件里NULL是一个宏定义#xff1a; 在函数重载同时出现int和char *参数版本的函数时#xff0c;使用NULL作为参数调用函数会调用int参数版本从0到NULL再到nullptr
传统C头文件里NULL是一个宏定义 在函数重载同时出现int和char *参数版本的函数时使用NULL作为参数调用函数会调用int参数版本而不是我们想要的char*参数版本。 引起该问的元凶是字面常量0的二义性既可以是一个整型也可以是一个无类型指针void*。除非对字面常量0进行强制类型转换b并调用否则编译器总是会优先把0看作是一个整型常量。
c出于兼容性考虑并没有消除字面常量0的二义性。但是引入了作为指针空值类型的常量nullptr指针空值类型被命名为nullptr_t。nullptr是关键字nullptr是有类型的只能被隐式转化为指针类型所以nullptr做参数可以成功调用char*版本的函数。
7.1.2 nullptr和nullptr_t
c11标准不仅定义了指针空值常量nullptr也定义了其指针空值类型nullptr_t。c11标准严格规定了数据间的关系
1.所有定义为nullptr_t类型的数据都是等价的行为也是完全一致的。
2.nullptr_t类型数据可以隐式转换成任意一个指针类型。
3.nullptr_t类型数据不能转换为非指针类型。
4.nullptr_t类型数据不适用于算术运算表达式。
5.nullptr_t类型数据可以用于关系运算表达式但仅能与nullptr_t类型数据或者指针类型数据进行比较当且仅当关系运算符为、、等时返回true。
7.1.3 一些关于nullptr规则的讨论
nullptr类型数据所占用的内存空间大小跟void*相同。
nullptr到任何指针的转换是隐式的而(void*)0则必须经过类型转换后才能使用。
nullptr_t对象的地址可以被用户使用。虽然nullptr也是一个nullptr_t的对象但它被定义为一个右值常量因此用户不能获得nullptr的地址。
7.2 默认函数的控制
7.2.1 类与默认函数
在c中声明自定义的类编译器会默认生成一些被称为默认函数的成员函数包括
构造函数、拷贝构造函数、拷贝赋值函数operator、移动构造函数、移动拷贝函数、析构函数。
c编译器还会为以下这些自定义类型提供全局默认操作符函数
operator ,operator operator operator *operator -operator -*operator newoperator delete。
一旦实现了这些函数的自定义版本则编译器不会再为该类自动生成默认版本。声明了带参的构造函数版本必须声明不带参版本以完成无参的变量初始化。声明了自定义版本的构造函数有可能导致自定义类型不再是POD的。
C11中可以在默认函数定义或者声明时加上 default来显式地指示编译器生成该函数的默认版本。另一方面有时候又希望可以限制一些默认函数的生成譬如有时候需要禁止使用拷贝构造函数c11中可以在默认函数定义或者声明时加上“ delete”来显式地指示编译器不生成函数的缺省版本。
7.2.2 “ default”与“ deleted”
c11中也可以在类定义外显式指定缺省版本这样可以对一个class定义提供多个实现版本通过选择性编译从而在提供缺省函数和自定义版本间切换。
c11并不要求编译器为“operator ”之类的函数提供缺省实现但是将其声明为显式缺省的话编译器会按照某些标准行为为其生成所需的版本。
显式删除可以避免用户使用一些不应该使用的类的成员函数也可以避免编译器做一些不必要的隐式数据类型转换例如 隐式删除不应该和explicit同用。在下面的例子中 显式删除导致显式构造的cc变量编译出错但是Func调用中编译器会尝试隐式地将char转为int从而调用一次ConvType(int)构造函数因而能通过编译。
显式删除并不局限于缺省版本的类成员函数或者全局函数上对于普通函数依然可以通过显式删除来禁止类型转换。
7.3 lambda函数
7.3.1 lambda的一些历史
7.3.2 c11中的lambda函数
lambda函数的语法定义 捕捉列表由多个捕捉项组成以逗号分割有如下形式
[var]表示值传递方式捕捉变量var[]表示值传递方式捕捉所有父作用域的变量[var]表示引用传递捕捉变量var。[]表示引用捕捉所有父作用域的变量。[this]表示值传递方式捕捉当前this指针。还可以进行组合例如[,a,b]表示引用传递方式捕捉a和b其他变量以值传递方式捕捉。
默认情况下lambda函数总是一个const函数mutable可以取消其常量性使用时参数列表不可省略。
不需要返回值的时候也可以连同符号-一起省略。
c11标准规定在块作用域以外的lambda函数捕捉列表必须为空而在块作用域中的lambda函数仅能捕捉父作用域中的自动变量。
7.3.3 lambda与仿函数
在c11之前我们在STL中会用到一种特别的对象称之为函数对象或者仿函数functor也就是重定义了成员函数operator()的一种自定义类型对象。在使用它的时候在代码层面跟函数的使用一样但本质却是一种对象。仿函数是编译器实现lambda的一种方式。现阶段通常编译器会把lambda函数转化为一个仿函数对象。 7.3.4 lambda的基础使用
lambda可用于实现局部函数。
7.3.5 关于lambda的一些问题及有趣的实验
如果需要捕捉的值称为lambda函数的常量通常需要使用按值传递的方式捕捉。反之需要捕捉的值称为lambda函数运行时的变量则应采用按引用方式进行捕捉。
lambda的类型并非简单的函数指针或者自定义类型lambda的类型被定义为闭包的类每个lambda表达式会产生一个闭包类型的临时对象右值。不过c标准允许lambda表达式向函数指针的转换前提是函数没有捕捉任何变量且函数指针所示的函数原型必须跟lambda函数有这相同的调用方式。
lambda函数的常量性及mutable关键字。现有c11标准中lambda等价的是有常量成员函数operator()的仿函数捕捉列表中的变量都会成为等价仿函数的成员变量而常量成员函数中改变其值是不允许的因而在按值捕捉的变量在没有声明为mutable的lambda函数中改变其会导致编译器报错。可以通过mutable修饰符消除其常量性不过更推荐使用引用捕捉。
7.3.6 lambda与STL
当循环次数较多时内联的lambda函数比函数指针性能好。函数指针应用范围相对狭小特别是需要具备一些运行时才能决定的状态时以前或许会使用仿函数现在则可以选用lambda。
7.3.7 更多的一些关于lambda的讨论
在现有c11中lambda不是仿函数的完全替代者这点很大程度上是由lambda的捕捉列表的限制造成的。仿函数可以被定义以后在不同的作用域范围内取得初始值这使得仿函数天生具有跨作用域共享的特征。lambda函数被设计的目的就是要就地书写就地使用。