![](https://img-blog.csdnimg.cn/20201014180756925.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
深入理解C++11新特性
文章平均质量分 66
小黑屋1024
这个作者很懒,什么都没留下…
展开
-
第2章 保持稳定性和兼容性
C++11中增加了以下宏:实际验证vs2017只支持__STDC_HOSTED__获取函数名。//main需要注意的是不支持在函数默认参数,因此此时__func__还没有被定义。int x = 3;// 一些代码...// 编译选项:g++ -std=c++11 2-1-5.cpp。原创 2023-12-18 09:28:00 · 38 阅读 · 0 评论 -
3.1 继承构造函数
C++11将通过using声明使用基类函数的方式扩展到了构造函数上,使得子类能够使用到父类一样的构造函数,这种构造方式称为继承构造函数。//继承构造private:int b{1};//就地初始化int main()/*print:A()A(int)*/原创 2023-12-18 09:28:33 · 133 阅读 · 0 评论 -
3.2 委托构造函数
构造函数在初始化列表位置,调用其他构造函数进行初始化,从而降低代码重复率,这样的构造函数成为委托构造函数,(在初始化列表位置)被调用的构造函数称为目标构造函数。class A {public:} //委托构造函数} //委托构造函数private:int main()A a,b(1);原创 2023-12-19 09:13:42 · 385 阅读 · 0 评论 -
3.3 右值引用:移动语义与完美转发
想要解决上述的问题,我们可以通过“偷”的方式,减少拷贝时内存分配,即将原有的资源浅拷贝到新对象的资源句柄上,而原资源置空,这样“偷”的方式叫做移动语义,这样的构造函数称为移动构造。只有再赋值给其他变量时,才会通过移动构造或者移动赋值,将a的资源移走,但是a依旧不会被释放,只不过因为移动语义的作用,其资源无法被访问了。实际上,默认的移动语义(移动构造)与拷贝并无区别,因此想要实现资源的移动构造,需要自己实现。此外,默认移动构造与拷贝构造并无区别, 所以想要实现资源移动的移动构造,需要自己实现。原创 2023-12-19 09:14:27 · 1002 阅读 · 0 评论 -
3.4 显示转换操作符
所谓自定义类型转换,是相对于标准隐式转换而言的,需要用户自己实现,分为转换构造函数和自定义类型转换函数。类似于构造函数,在类A中形如的成员函数,意味着可以将A隐式转换为A类型。class A {};B b = a;testA(b);//自定义类型转换如上面的例子,20行的testA函数需要A类型的参数,这里传入了b也可以完成调用,是因为发生了隐式类型转换。风险:上面的testA()函数可能还看不到什么危害较大的风险。原创 2023-12-20 11:25:46 · 366 阅读 · 0 评论 -
3.5 列表初始化
从C++11开始,以花括号的集合(列表)进行初始化称为列表初始化。原创 2023-12-20 11:26:48 · 352 阅读 · 0 评论 -
3.6 POD类型
所谓POD,全称为Plain Old Data,表示普通的旧数据类型,这种类型不存在C++的虚函数和许捷诚等数据,体现了其与C的兼容,可以使用用最老的memcpy()函数进行复制,使用memset()进行初始化等。原创 2023-12-23 11:44:38 · 374 阅读 · 0 评论 -
4.1 右尖括号>的改进
而在C++11将这个限制取消,要求编译器“智能”判断是什么类型。当然,正常场景下也不会这么用,此外,如果真的出现这样的场景,我们还可以将1>>5用括号包裹,提高优先级,从而解决。很显然,我们需要的是右移操作,但是由于C++11对于右移操作符的优化,上面代码会报错。C++11之前对于双右尖括号优先解析为右移操作符,因此一些场景下会导致编译报错,所以,在之前需要在这些场景下将两个>用空格分隔。原创 2023-12-22 15:43:52 · 407 阅读 · 0 评论 -
4.2 auto类型推导
上述代码radius未float类型,而在经过计算之后得到的circumference精度得到了扩展(double),而有时我们容易依赖原有类型将circumference声明为float类型,这就使得计算结果精度降低了。auto在进行类型推导时,会对auto后冗余的*进行忽略,如p通过自动推导为int *,而auto*则不会被认为是int **,而是int *。3)声明auto数组。我们可以看到,main中的x是一个数组,y的类型是可以推导的,而声明auto z[3]这样的数组同样会被编译器禁止。原创 2023-12-21 09:03:20 · 686 阅读 · 0 评论 -
4.3 decltype
可以推导模板的返回类型从而使用引用参数获取返回值,当然这里仍然需要声明实参,所以还是需要知道具体类型,用法比较鸡肋,牛逼的是后面的追踪返回类型。decltype能够继承cv限制符、引用和指针,但是只是针对声明本身,对于对象如果是cv的,其成员类型于成员本身是否cv有关(下例的a.i)而在C++11中,又增加了hash_code这个成员函数,返回该类型唯一的哈希值,以供程序员对变量的类型随时进行比较。对于cv以及&,如果推导的类型已经有了,而又指定了,则通常会忽略decltype()后的cv和&。原创 2023-12-21 09:04:07 · 783 阅读 · 0 评论 -
4.4 追踪返回类型
这一条通常是对于多层函数而言(更像是面试题)// 有的时候,你会发现这是面试题// auto (*)() -> int(*) () 一个返回函数指针的函数(假设为a函数)// auto pf1() -> auto (*)() -> int (*)() 一个返回a函数的指针的函数// 1定义了两个类型完全一样的函数pf和pf1。其返回的都是一个函数指针。而该函数指针又指向一个返回函数指针的函数。这一点通过is_same的成员value已经能够确定了。原创 2023-12-22 15:43:22 · 551 阅读 · 0 评论 -
4.5 基于范围的for循环
值得指出的是,使用范围for需要一些条件。首先,要求被迭代的对象的范围是可确定的,比如容器累的begin,end,或者是数组的起始位置和结束位置,这些都是用于确定遍历范围。范围for分为两部分,前者ele为迭代元素(注意不是迭代器,是可以直接访问的元素),后者eles则是被遍历的容器。对于正常的stl和内置数组而言,都是符合这些要求的,但是如果用户自己实现,则需要注意实现这些内容。但是上述两种方式都需要告诉循环体其界限的范围。当然需要注意auto不会推导引用,需要自己写。原创 2023-12-23 11:23:57 · 414 阅读 · 0 评论 -
5.1 C++11强类型枚举
强枚举类型也是可以匿名的,但是由于其枚举成员需要通过作用域访问,因此匿名强枚举类型可能无法访问成员,当然也可以使用decltype获取类型。因为C的枚举是基于常量数值设计的,所以总是可以被隐式转为int,所以在算数运算(没有什么意义)和比较运算时,容易出错。枚举值和类型都是全局可见的, 与正常C++的namespace、类等都是格格不入的,并且还容易导致冲突。其次,在C++11中,枚举成员的名字除了会自动输出到父作用域,也可以在枚举类型定义的作用域内有效。原创 2023-12-16 11:33:11 · 72 阅读 · 0 评论 -
5.2 C++11堆内存管理:智能指针与垃圾回收
通过引用计数的方式,每有一个指针引用此内存时,计数+1,相反,每有一个指针不再引用此内存时,计数-1。第一步扫描,第二步移动,移动的方式是将空间分成from和to两部分,将当前活的对象坐在区域为from,然后移动到to空间内,然后将from空间清空,并将from和to的定义互换。C++一些垃圾回收的库,但是由于指针的灵活性(指针可能做了移动,但是原来的内存并不一定被释放,可能还会移回继续使用原来的内存),所以只是最小垃圾回收支持。指针指向的内存释放之前,先释放了指针,导致那块内存无法访问,且无法重新使用。原创 2023-12-16 11:32:22 · 97 阅读 · 0 评论 -
6.1 C++11 常量表达式
而对于j,如果不是有代码显式地使用了它的地址,编译器可以选择不为它生成数据,而仅将其当做编译时期的值(是不是想起了光有名字没有产生数据的枚举值,以及不会产生数据的右值字面常量?对于浮点数常量,由于编译时和运行时环境可能不同,这样就会导致浮点数常量的精度可能有所变化,因此在C++11中,要求编译时的浮点常量表达式值的精度要至少等于(或者高于)运行时的浮点数常量的精度。而由于constexpr的编译时常量性,使得对于递归的常量表达式函数的使用,并不会带到运行时展开计算,而是在编译时直接计算好结果进行替换。原创 2023-12-13 21:42:34 · 81 阅读 · 0 评论 -
6.2 C++11变长模板
对于声明了的变长模板参数包Args,如果我们使用Args&&...的方式解包,意味着展开后的参数为Arg1&&,Arg2&&,...,Argn&&。C++11引入变长模板的同时,扩展了sizeof,引入了sizeof...,用于计算参数包的参数个数,需要注意的是传入的参数为包名,而非形参名。值得注意的是,在C++11中,标准要求函数参数包必须唯一,且是函数的最后一个参数(模板参数包没有这样的要求)。值得注意的是,在C++11中,标准要求函数参数包必须唯一,且是函数的最后一个参数(模板参数包没有这样的要求)原创 2023-12-15 09:13:10 · 68 阅读 · 0 评论 -
6.3 C++11 原子操作与原子类型
创建自定义类型的原子类型,当然也可以使用此方式创建内置类型的原子类型。atomic为作为类模板,提供了统一的操作接口:其中is_lock_free用于判断是否有锁,load用于读取,store用于存,exchange用于交换数据。由于原子类型属于资源类型,所以为了避免拷贝时引起的问题,atomic类模板删除了相关的拷贝构造和赋值函数。此外,atomic到原始类型的转换也是允许的(隐式的),但非原子操作。原创 2023-12-13 21:43:24 · 853 阅读 · 0 评论 -
6.4-6.5 C++11线程局部存储与快速退出:quick_exit与at_quick_exit
上面的例子中使用全局的errorCode作为错误码,这样方便保存线程中的错误码,但是对于多线程二线,可能存在错误码覆盖的问题,比如thread1的错误码1和thread2的错误码-1可能会相互覆盖。C++中存在正常退出和异常退出两种情况,其中异常退出主要是对于发生异常而未被捕获时产生,此时会调用terminate,而terminate默认行为是调用abort函数终止程序,当然也可以通过set_terminate修改默认行为。C++11对TLS标准做出了一些统一的规定。原创 2023-12-14 17:20:11 · 144 阅读 · 0 评论 -
7.1 C++11指针空值—nullptr
比较运算也有区别,nullptr可以与任意指针或nullptr_t类型以及0比较(非0整数不允许),而NULL可以与整数和指针比较。nullptr可以隐式转换为任意指针类型,而NULL需要显示转换。nullptr_t类型是由nullptr获取的。NULL可以进行算数运算,nullptr不行。NULL是宏定义,nullptr是关键字。原创 2023-12-11 09:13:19 · 65 阅读 · 0 评论 -
7.2 C++11默认函数的控制
按explicit的本意是无法通过编译的,但是此处添加了=delete之后,反而移除了explicit的本意。而言,对于Func('a');显示缺省,对于默认生成的函数而言,并不是默认所有都会生成,而是在需要时才会生成。而且当用户自己实现其中的某个函数时,编译器就会移除相应的默认函数,这样就会导致类变得不是POD了。C++11提供了=default关键字,用于默认函数定义之后,表示要求编译器生成对应的默认函数,从而确保类的POD。除此之外,还可以用于删除new函数,使得类只能创建于栈,而不能创建于堆上。原创 2023-12-11 09:14:26 · 151 阅读 · 0 评论 -
7.3 lambda函数
而lambda较for_each而言,首先其函数内容会直接放在调用处,可阅读性更高(当然,有时也会被分离出来并命名,但通常不会太远);其次使用函数指针很可能导致编译器不对其进行inline优化(inline对编译器而言并非强制),在循环次数较多的时候,内联的lambda和没有能够内联的函数指针可能存在着巨大的性能差别。lambda函数中不同的捕获传递方式会造成不同的结果,对于值传递,则在传递的值在编译期就确定了,无法被修改,而对于引用传递则可以同步lambda函数外的修改。原创 2023-12-15 09:12:22 · 370 阅读 · 0 评论 -
8.1 C++11对齐支持
很显然,这样在push_back时,将一个对齐值为32的ColorVector塞到对齐值只有1的arrCV.data中,可能会导致一些性能上的丢失(虽然这里我实验了一下也没有什么区别~~~)代码中成员a占1个字节,成员b占4字节,而通过offsetof(用于获取成员变量在类中的偏移量),查看a,b成员位置时,b的位置为4而不是1,这是因为C/C++对数据结构有着对齐要求。内存对齐是一个整数,意味着该数据成员地址只能位于内存对齐的倍数上,如b位于4而非1。原创 2023-12-07 15:18:57 · 119 阅读 · 0 评论 -
8.2 C++11通用属性
上述例子中因为函数Func中的条件语句有悬挂(else没有处理),所以当传入0时,并不会抛出异常终止程序,与noreturn的属性冲突,执行了12行代码,但是最终在return时发生异常崩溃。随着C++语言的演变和编译器的发展,人们常常发现C++的标准提供的语言能力不能完全满足要求,因此各大编译器厂商为了满足客户需求,设计出一系列语言扩展来扩展语法,比较常见的就是“属性”。用于标识不会返回的函数的。主要用于那些不会将控制流返回到调用函数的函数,如终止程序的函数,无限循环语句的函数,抛出异常的函数等。原创 2023-12-07 15:20:05 · 48 阅读 · 0 评论 -
8.3 C++11对Unicode的支持
在C++98中,引入wchar_t对Unicode支持,但是后来由于不同平台下wchar_t的宽度并不相同(8,16,32位),导致可移植性受到影响。此外,对于多个连续声明的字符串常量,只要有一个有前缀,则编译器会将这些连续的字符串常量都以此前缀处理。(实际上vs2017并不允许)通常情况下,对于连续的字符串常量,C++会要求编译器将其连起来,比如"a" "b"和"ab"没有区别。以上三种,再加上wchar_t格式的L以及不带前缀的字符串,C++11则包含了5种字符串常量的前缀。原创 2023-12-07 15:20:37 · 237 阅读 · 0 评论