C++ 11 新特性

目录

  • 1. 支持特性的编译器版本
  • 2. 模板表达式中空格
  • 3. 空指针
  • 4. auto
  • 5. 统一初始化
  • 6. explict
  • 7. 范围for
  • 8. =default,=delete
  • 9. 化名模板(alias template)
  • 10. using
  • 11. noexcept
  • 12. override
  • 13. final
  • 14. decltype
  • 15. lambda
  • 16. Variadic Templates(可变参数模板)
    • 16.1 可变参数函数模板
      • 16.1.1 不同类型参数的分解
      • 16.1.2 同类型参数的分解
    • 16.2 可变参数类模板
      • 16.2.1 递归继承参数分解
      • 16.2.2 递归内含参数分解
      • 16.2.3 头尾元素处理方式不同
  • 17. 右值引用
  • 18. unorderd容器
  • 19. tuple类型

1. 支持特性的编译器版本

(1)不同编译器版本支持的C++新特性可在 https://zh.cppreference.com中查看:
在这里插入图片描述
在这里插入图片描述
(2)可以在cpp程序中打印宏定义“__cplusplus”,看当前编译器支持C++ 98、C++ 11、C++ 14等。
在这里插入图片描述

2. 模板表达式中空格

          C++ 11之前,模板表达式中两个方向相同的尖括号必须用空格隔开,否则会被编译器解析为流操作符>>。C++ 11后,无需用空格隔开。
在这里插入图片描述

3. 空指针

          C++ 11之前,指针初始化或者处理空指针都是将其赋值为0或NULL。该方法有一种缺陷,即这种赋值下的指针可以被当作一个整数值使用,缺少了指针类型这一性质。C++ 11后,初始化或者处理空指针应该用nullptr,其附有指针类型的性质。
在这里插入图片描述

4. auto

          auto关键字可以让编译器自动进行类型推导,主要用于代替长和复杂表达式的类型书写
在这里插入图片描述

5. 统一初始化

          C++中初始化变量和对象的方式有( ),{ },=。其中,{ }可以进行任何变量和对象的初始化:变量类型 变量名 {初始化参数 }。底层采用的是initialzer_list接收初始化参数。C++中编译器将{ 参数…}打包为initialzer_list对象
在这里插入图片描述

  • { }可以用来设初值
    在这里插入图片描述

  • { }不允许窄化参数,否则编译器可能会warning或error:
    在这里插入图片描述

std::initializer_list是标准库中的一个模板,所有的标准容器的构造函数都有以initializer_list为参数的构造函数。
在这里插入图片描述

  • 通过将initializer_list作为函数的形参,可以给函数传输任意数量的参数,在函数内部可用initializer_list的迭代器对每个参数进行遍历。

  • initializer_list底层为一个array,里面存储每个参数的指针,可以将其看作一个辅助容器。

  • 由于initializer_list构造函数是private,所以其只能由编译器调用并构造出initializer_list对象。

  • 当具有特定个数参数的重载函数与有initializer_list参数的重载函数共同存在,并且输入该特定个数的参数时,有initializer_list参数的重载函数优先被调用

  • 如果没有接收initializer_list参数版本的function函数,也可以用{ }传递参数,只不过编译器会将{ }中的参数拆解,寻找符合调用的function
    在这里插入图片描述

initializer_list应用的例子:

在这里插入图片描述

6. explict

          explict关键字一般用于修饰构造函数,阻止编译器隐式利用class A的构造函数将其他类型的数据转换为class A类型的对象。C++ 11之前,explict仅阻止编译器将单一参数(只有一个待定的参数)的构造函数作为类型隐式转换的工具。C++ 11之后,explict可以阻止有多个参数的构造函数作为类型隐式转换的工具
在这里插入图片描述
在这里插入图片描述
          我在侯捷老师在多参数验证explict的结果上有一些不一样的观点。两个红色框框在支持C++ 11版本的g++编译器是并未报错。除非将接收initializer_list参数的构造函数注释掉,才出现如上图的结果。因为复制初始化列表 P p3 = {77, 5, 44},应该首先用{77, 5, 44}生成initializer_list对象,之后需要initializer_list对象隐式转换为P对象,无论如何也不会去调用显式的explicit P(int a, int b, int c)构造函数,只会隐式调用P(initializer_list<\int>)。

#include <iostream>using namespace std;
class P
{
public:P(int a, int b){cout<< "P(int a, int b) \n";}P(initializer_list<int>){cout<<"P(initializer_list<int>) \n";}explicit P(int a, int b, int c){cout<<"explicit P(int a, int b, int c) \n";}
};
void fp(const P&) {};int main()
{P p1 = {77, 42};P p3 = {77, 5, 44};P p2 (77, 5,2);fp( P{47, 11} );fp( P{77,5,42});cout<<__cplusplus<<endl;return 0;
}

在这里插入图片描述

7. 范围for

          范围for可用于遍历容器里面的元素,简化书写。依次从coll容器中取出元素赋值给decl变量(可能存在隐式转换,如果不想发生请将引起隐式转换的构造函数声明为explicit)。不过赋值过程是拷贝。如果需要实际操作容器中的元素,则需要将decl变量声明为引用。set、map等容器不允许通过迭代器改变元素值,因此无法使用范围for。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

8. =default,=delete

          C++编译器有时候会为类声明一些默认成员函数(默认构造、拷贝构造、move拷贝构造、拷贝赋值、move拷贝赋值、析构函数、操作符函数)。如果实现了这些函数的自定义版本后,编译器就不会去生成默认版本。大多数时候,我们需要声明带参数的构造函数,此时编译器就不会为其生成默认构造函数(无参)。如果此时还是希望编译器能帮我们自动生成一个默认构造(无参),则可以使用=default告诉编译器。=default可以用于默认构造、拷贝构造、move拷贝构造、拷贝赋值、move拷贝赋值、析构函数如果类中有指针成员,那么需要自行撰写上述特殊成员函数;若无指针成员,则可以直接使用默认

class Example
{
public:Example() = default;  // 编译器将为其生成一个默认构造函数Example(int i) : data(i) {}private:int data;
};

有时候可能不希望让编译器悄悄地帮我们生成一个默认函数,C++ 11可以直接令函数=delete,告诉编译器不要帮我生成该默认函数,=delete也可以禁止某函数被使用,可用于任何成员函数

  • 禁止类型隐式转换,也可以用在普通函数上。
class Example
{
public:Example(int i) {}Example(char c) = delete;
};
int main()
{Example t1(1);
//   Example t2('a');  // 无法通过编译,由于重载特性,优先调用最佳匹配函数Example(char c),但该函数为delete
}
  • 禁止对象被拷贝:以前可以将拷贝构造、拷贝赋值声明为private来实现禁止对象被拷贝,现在可以使用delete实现。
    在这里插入图片描述
    在这里插入图片描述

9. 化名模板(alias template)

          化名模板是给模板起一个别名,本质上还是模板
在这里插入图片描述

  • 可以简化模板书写

  • 个模板被当作另一个模板的模板参数时,可以用模板的化名,以化名将模板本身传入另一个模板的模板参数中。直接传入模板的名字或者临时对象,编译器均不认识,因为一般编译器只对实例化后的模板对象进行拷贝传递;
    在这里插入图片描述
              采用模板的化名传递模板,作为模板的模板参数
    在这里插入图片描述

  • 不允许对化名模板做特化
              化名模板类似于模板的typedef,但比模板的typedef更强大,typedef不接受变化的参数,而化名模板可以。
    在这里插入图片描述

10. using

          using关键字可以用于展开命名空间,声明类成员。C++ 11后,using还可以被用于类型化名(类似typedef),化名模板
在这里插入图片描述
在这里插入图片描述

11. noexcept

          noexcept关键字用于表示一个函数或表达式在执行期间是否会抛出异常,相当于函数或表达式的作者对编译器和使用者承诺绝不抛出异常,从而使得编译器可以对其进行优化、方便使用者调式代码。noexcept后面可以紧跟一个条件判断结果,表示在条件判断为真的情况下,该函数绝不抛出异常。
在这里插入图片描述
          下例表示如果x.swap(y)函数不抛出异常,外层的swap()函数就绝不会抛出异常。
在这里插入图片描述
          当使用自动增长型的容器(例如vector、deque等)时,标准库容器为了提高效率会调用move copy,前提是容器存放的元素对象的move copy构造和move copy赋值被声明为noexcept,否则标准库容器将不会使用move copy。
在这里插入图片描述

12. override

          override关键字表示如果派生类在虚函数声明时使用了override描述符,那么该函数必须重载其基类中的同名函数,否则代码将无法通过编译。避免程序员将需要重写的函数写错为重载。
在这里插入图片描述

13. final

          当final关键字用于修饰类时,声明该类已经是整个继承体系的最后一种派生类了,其他类将无法继承该类
在这里插入图片描述

          当final关键字用于修饰虚函数时,声明该类已经是整个继承体系中最后一个能重写该虚函数的派生类了,后续继承该类的派生类中不允许在重写该虚函数了。
在这里插入图片描述

14. decltype

          decltype可以获取对象或表达式的类型。类似的关键字有typeof,但是它不是标准库中的。

  • 获取对象类型:
    在这里插入图片描述

  • 获取表达式(包括lambda表达式)类型:(下例表明返回值类型为x+y的类型)
    在这里插入图片描述
    在这里插入图片描述

15. lambda

          lambda表达式被用来创建一个匿名函数,加上()后表示调用,可替换独立函数或者函数对象,基本上可以等效于仿函数对象。lambda表达式的格式如下:
在这里插入图片描述

  • […]为取用外部的数据变量,里面的数据是在lambda表达式创建的时候就于其绑定好了,默认是拷贝赋值[=],[&]表示将外部的数据变量以引用的形式绑定到lambda表达式上
  • (…)为lambda表达式被调用时传入的新参数,无传入参数则可以不写(),前提是mutable、throwSpec、retType都不写
  • mutable关键字表示[…]中的数据是可以被改写的,一般[=]拷贝得到的数据均是可以改写的,因此也要配套使用mutable关键字,[&]的参数无需用mutable
  • throwSpec表示是否抛出异常;
  • ->表示后面将要写返回值类型
  • retType为lambda返回值类型
    例子:
    在这里插入图片描述
    在这里插入图片描述
               由于lambda本身是一种C++ 语法,并不是真正的类对象,没有构造函数等等。所以不建议用lambda来构造其他对象,因为如果构造其他对象时没有传入lambda实例,其他对象的构造函数可能会去调用lambda构造函数,从而导致报错。
    在这里插入图片描述
              标准库中,lambda表达式最常用在一些algorithm中,当作仿函数传入算法中进行执行,效率比真实的仿函数高一点点。
    在这里插入图片描述

16. Variadic Templates(可变参数模板)

16.1 可变参数函数模板

          在 Variadic Templates中,模板参数个数可以是不固定的,下例中,用typename T来表示模板的第一个参数,用typename… Types表示模板剩余的所有模板参数(简称模板参数包)。注意模板参数包声明时…与传入模板函数时的…位置不一样。可变参数模板根据所传入的模板参数进行实例化。

template <typename T, typename... Types>
void printx( const T& firstArg, const Types&... args){cout << firstArg << endl;l l print first argumentprintX(args...);
}

16.1.1 不同类型参数的分解

          可变参数模板有一个重要的应用,就是结合递归调用模板自身,将所有的模板参数一一分解开来,分别进行处理。下例中,print函数模板参数由一个固定模板参数T和一个不固定模板参数包Types组成,print实例中有四个模板参数,那么print第一个模板实例就是接收firstArg接收第一个参数7.5,剩下的三个参数全部由args接收。print内部又将包含剩余参数的参数包作为参数递归调用print。递归调用的第一个print将收到第一个参数为“hello”,和剩下两个参数组成的参数包,总是分解成1+若干参数…,直到递归分解直至调用终止的无参print( )函数
在这里插入图片描述

  • sizeof…(args)输出args参数个数;
  • 在同一个函数的不同模板中,template<typename T, typename… Types>比template<typename… Types>更特化,因此上例中只会调用1和2。

16.1.2 同类型参数的分解

          若需要分解的参数是同类型的,那么可以直接用initializer_list替换可变参数模板
在这里插入图片描述
在这里插入图片描述

16.2 可变参数类模板

16.2.1 递归继承参数分解

          可变参数模板也可以用在类模板中,一个常用的技巧就是通过递归继承分解模板参数。C++新特性中tuple就是利用了这中技巧。tuple容器可以将不同数据类型的元素放在一个容器中。其基本原理是将模板参数分解为1+args(若干参数),创建第一个类型参数的成员,并继承只包含args参数的模板类,从而依次递归实现不同类型参数的分离与成员变量的创建。当需要对tuple对象取元素时,直接将子类的指针转换为指向父类的指针即可。如下图所示(typename Head::type 可直接改为Head(本就是参数类型,内置类型无::type,例如无int::type)):
cc

16.2.2 递归内含参数分解

          与递归继承不同,可以采用递归内含剩余模板参数类型的类,实现分解不同模板参数并构造对应的对象
在这里插入图片描述

16.2.3 头尾元素处理方式不同

          当处理头尾参数与处理中间参数的方式不同时,则可以借用可变参数模板分解参数的同时,根据参数的索引序号进行特殊处理,其中是否是尾参数可用sizeof…()获取可变参数个数
在这里插入图片描述

17. 右值引用

         首先需要理解左值与右值:

  • 左值为存储在内存中、有明确存储地址(可取地址)的数据;另一种分辨方法就是能够出现在‘=’的左边的为左值
  • 右值为可以提供数据值的数据(不可取地址);另一种分辨方法是只能出现在‘=’的右边的为右值(规定临时对象是一种右值)
    在这里插入图片描述

         右值引用是C++ 11的新特性,它是对一个右值进行引用的类型(&&),主要为了避免不必要的拷贝造成资源的浪费和参数转发。由于右值是匿名的,因此只能通过引用它的方式找到它。通过右值引用的声明,该右值又”重获新生”(相当于给匿名对象重新起了名字且不会马上析构),其生命周期与右值引用类型变量的声明周期一样,因此“右值引用的结果”是左值当右值出现在赋值符号‘=’的右侧时,我们认为可以让编译器将右值的资源直接搬移(偷取)给左值而不需要重新拷贝再析构右值。右值引用一般用于撰写move版本的copy构造函数和move版本的copy 赋值函数,内部实现只是将原来指向资源的指针赋值为null,新对象的指针接管原来的资源,本质上是一个浅拷贝过程,因此效率高。输入是右值且要执行拷贝动作时,优先调用move版本的拷贝构造函数。
在这里插入图片描述
         标准库中std::move()函数可以将左值转换为右值,但是使用者必须确保后续不再使用被转换的左值(左值的资源已经被转移走了)。下例中,调用普通拷贝构造函数构造c1,调用move拷贝构造函数(右值引用)构造c2且后续不允许再使用
在这里插入图片描述

         当存在多层函数嵌套调用时,参数的右值特性可能会被丢失。标准库中std::forward()函数用于保持参数类型信息的完美转发
在这里插入图片描述
在这里插入图片描述
         调用std::forward时,根据参数的左值或右值属性,编译器会选择适当的模板实例进行转发。下图为std::forward源码。如果输入参数是一个左值引用(int &),std::forward将返回一个左值引用(int & && 折叠为 int &)。如果参数是一个右值引用(int &&),std::forward将返回一个右值引用(int && && 折叠为int &&)
在这里插入图片描述
         根据模板类型推导,如果输入参数是一个左值引用(int &),__t和std::remove_reference<_Tp>::type &的类型为int &,std::remove_reference<_Tp>::typede 类型为int , 则_Tp为int & ,因此返回值转型为_Tp&&,即为int & &&,根据折叠原理折叠为int &。同理输入右值引用的到int &&。

完整的带move拷贝的类例子:
在这里插入图片描述
在这里插入图片描述

18. unorderd容器

         C++ 11后,将原来的无序容器名字进行了更换
在这里插入图片描述

         用到底层由哈希表实现的容器时,需要传入一个计算hash值的函数对象。由于有的对象可能包含许多不同类型的成员变量,如何计算hash值存在困难。一种万用的hash function如下:
在这里插入图片描述

19. tuple类型

         tuple是C++11新标准的类型。tuple可以存放任意个数任意类型的元素, 可以使用直接初始化, 和"make_tuple()"初始化, 访问元素使用"get<>()"方法, 注意get里面的位置信息, 必须是常量表达式(const expression);
在这里插入图片描述
(本文为学习侯捷老师C++2.0新特性课程后的笔记)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/191076.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity Hub无法登陆的两种终极解决办法

最近换了个电脑&#xff0c;需要重装Unity&#xff0c; 然后unity hub 怎么都无法登陆&#xff0c;登陆不了就不能激活personal license。试了很多次&#xff0c;包括unity hub 2.5.8 和unity hub 3.3都不行&#xff0c;真的是很崩溃。因为是公司的电脑&#xff0c;限制比较多&…

Android 基本属性绘制文本对象FontMetrics

FontMetrics对象 它以四个基本坐标为基准&#xff0c;分别为&#xff1a; ・FontMetrics.top ・FontMetrics.ascent ・FontMetrics.descent ・FontMetrics.bottom 如图: 要点如下&#xff1a; 1. 基准点是baseline 2. Ascent是baseline之上至字符最高处的距离 3. Descent是ba…

聚观早报 |京东11.11公布成绩单;2023数字科技生态大会

【聚观365】11月13日消息 京东11.11公布成绩单 2023数字科技生态大会 TikTok深受英国中小企业青睐 周鸿祎称大模型2年内可“进”智能汽车 双11全国快递业务量达 6.39 亿件 京东11.11公布成绩单 京东11.11公布成绩单&#xff1a;截至11月11日晚23:59&#xff0c;2023年京东…

【Kettle实战】数据分批处理及参数化传递子作业任务

对于大表操作&#xff0c;本来离线数据需要分批处理&#xff0c;刚开始只会用具体日期去做&#xff0c;通过复制多分转换和作业来处理。当日期范围大了后&#xff0c;这是个苦力活儿&#xff0c;kettle里面有参数化传递功能&#xff0c;多动手实操&#xff0c;懂得灵活变通自然…

2023数字科技生态展,移远通信解锁新成就

11月10日&#xff0c;以“数字科技&#xff0c;焕新启航”为主题的中国电信2023数字科技生态大会暨2023数字科技生态展在广州盛大启幕。作为物联网行业的龙头标杆&#xff0c;同时更与中国电信连续多年维持稳定友好的合作关系&#xff0c;移远通信受邀参加本次展会。 在本次展会…

Rust 中的引用与借用

目录 1、引用与借用 1.1 可变引用 1.2 悬垂引用 1.3 引用的规则 2、slice 类型 2.1 字符串字面量其实就是一个slice 2.2 总结 1、引用与借用 在之前我们将String 类型的值返回给调用函数&#xff0c;这样会导致这个String会被移动到函数中&#xff0c;这样在原来的作用域…

Java设计模式-结构型模式-代理模式

代理模式 代理模式静态代理动态代理JDK动态代理CGlib动态代理 代理模式 创建一个代理对象来控制对原始对象的访问&#xff0c;可以用来扩展原始对象的功能&#xff0c;同时保护原始对象 一般使用代理模式的目的有两个&#xff1a; 保护目标对象增强目标对象 代理模式有两种实现…

MATLAB | 官方举办的动图绘制大赛 | 第一周赛情回顾

嘿真的又是很久没见了&#xff0c;最近确实有点非常很特别小忙&#xff0c;今天带来一下MATHWORKS官方举办的迷你黑客大赛第三期(MATLAB Flipbook Mini Hack)的最新进展&#xff01;&#xff01;目前比赛已经刚好进行了一周&#xff0c;前两届都要求提交280个字符内的代码来生成…

JVM字符串常量池StringTable

目录 一、StringTable为什么要调整 二、String的基本特性 三、String的内存分配 四、字符串拼接操作 五、intern()方法 六、Stringtable的垃圾回收 七、G1中String去重操作 一、StringTable为什么要调整 jdk7之前&#xff0c;hotspot对于方法区的实现是永久代&#xff…

尝试使用php给pdf添加水印

在开发中增加pdf水印的功能是很常见的&#xff0c;经过实验发现这中间还是会有很多问题的。第一种模式&#xff0c;采用生成图片的方式把需要添加的内容保存成图片&#xff0c;再将图片加到pdf中间&#xff0c;这种方法略麻烦一些&#xff0c;不过可以解决中文乱码的问题&#…

互联网Java工程师面试题·微服务篇·第三弹

目录 34、什么是端到端微服务测试&#xff1f; 35、Container 在微服务中的用途是什么&#xff1f; 36、什么是微服务架构中的 DRY&#xff1f; 37、什么是消费者驱动的合同&#xff08;CDC&#xff09;&#xff1f; 38、Web&#xff0c;RESTful API 在微服务中的作用是什…

SpringCloud微服务:服务拆分

不同的数据库之间&#xff0c;如何共同调用&#xff1f;接下来讲讲两个数据库之间如何交互 1、微服务需要根据业务模块拆分&#xff0c;做到单一职责,不要重复开发相同业务 2、微服务可以将业务暴露为接口&#xff0c;供其它微服务使用 3、不同微服务都应该有自己独立的数据库…

(头哥)多表查询与子查询

目录 第1关&#xff1a;查询每个学生的选修的课程信息 第2关&#xff1a;查询选修了“数据结构”课程的学生名单 第3关&#xff1a;查询“数据结构”课程的学生成绩单 第4关&#xff1a;查询每门课程的选课人数 第5关&#xff1a;查询没有选课的学生信息 第6关&#xff1a…

【算法】新的开始(Kruskal算法,虚拟源点)

题目 发展采矿业当然首先得有矿井&#xff0c;小 FF 花了上次探险获得的千分之一的财富请人在岛上挖了 n 口矿井&#xff0c;但他似乎忘记了考虑矿井供电问题。 为了保证电力的供应&#xff0c;小 FF 想到了两种办法&#xff1a; 在矿井 i 上建立一个发电站&#xff0c;费用…

VB.NET三层之用户查询窗体

目录 前言: 过程: UI层代码展示: BLL层代码展示: DAL层代码展示: 查询用户效果图:​ 总结: 前言: 想要对用户进行查询&#xff0c;需要用到控件DataGrideView&#xff0c;通过代码的形式将数据库表中的数据显示在DataGrideview控件中&#xff0c;不用对DatGridView控件…

探索向量数据库 | 重新定义数据存储与分析

随着大模型带来的应用需求提升&#xff0c;最近以来多家海外知名向量数据库创业企业传出融资喜讯。 随着AI时代的到来&#xff0c;向量数据库市场空间巨大&#xff0c;目前处于从0-1阶段&#xff0c;预测到2030年&#xff0c;全球向量数据库市场规模有望达到500亿美元&#xff…

20.有效的括号(LeetCode)

思路&#xff1a;用栈的后进先出的特性&#xff0c;来完成题目的要求 因为C有库&#xff0c;可以直接用&#xff0c;而C语言没有&#xff0c;所以我们直接把写好的栈拷贝上来用。 首先&#xff0c;完成框架的搭建 其次&#xff0c;再实现循环内的部分。1.左括号入栈 2.右括…

数据分析实战 | KNN算法——病例自动诊断分析

目录 一、数据及分析对象 二、目的及分析任务 三、方法及工具 四、数据读入 五、数据理解 六、数据准备 七、模型训练 八、模型评价 九、模型调参 十、模型改进 十一、模型预测 一、数据及分析对象 CSV文件——“bc_data.csv” 数据集链接&#xff1a;https://dow…

HTML简单介绍

且视他人之疑目如盏盏鬼火&#xff0c;大胆地去你的夜路。 目录 1.网页 2.Web标准 3.HTML 3.1HTML结构 3.2HTML标签​编辑 4.标签介绍 4.1排版标签 4.2文本格式化标签 4.3媒体标签 4.3.1图片标签 4.3.2 音频标签 4.3.3视频标签 5.相对路径 6.链接标签 6.1target属…

车载通信与DDS标准解读系列(1):DDS-RPC

▎RPC & DDS-RPC RPC&#xff1a;Remote Procedure Call&#xff0c;远程过程调用。 远程过程调用是一种进程间通信&#xff0c;它允许计算机程序在另一个地址空间中执行子程序&#xff0c;就好像用别人的东西像用自己的一样&#xff0c;常用于分布式系统。 远程过程调用…