C++ 11 新特性

news2024/12/24 9:53:18

目录

  • 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.coloradmin.cn/o/1204581.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

4.2每日一题(求多元函数在某一点的微分)

1、分别求x和y的偏导&#xff0c;再相加即可 2、因为多元函数的表达式不方便求偏导&#xff0c;所以可以使用先代后求法&#xff1a; &#xff08;1&#xff09;对x偏导&#xff1a;把y0代入&#xff0c;很容易求出对x偏导的结果 &#xff08;2&#xff09;对y偏导&#xff1a…

Django——路由层

一. 路由匹配 1. 路由匹配注意事项 urlpatterns [url(r^admin/, admin.site.urls),# 首页url(r^$,views.home),# 路由匹配url(r^test/$,views.test),url(r^testadd/$,views.testadd),# 尾页(了解): 后期使用异常捕获处理, 这样的尾页让django的第二次在路径中斜杠APPEND_SL…

Redis解决缓存问题

目录 一、引言二、缓存三、Redis缓存四、缓存一致性1.缓存更新策略2.主动更新 五、缓存穿透六、缓存雪崩七、缓存击穿1.基于互斥锁解决具体业务2.基于逻辑过期解决具体业务 一、引言 在一些大型的网站中会有十分庞大的用户访问流量&#xff0c;而过多的用户访问对我们的MySQL数…

Linux SSH免密登录

目录 简介 创建Linux用户和用户组 配置LINUX静态IP 编辑IP映射 SSH免密登录配置 登录测试 简介 SSH&#xff08;Secure shell&#xff09;是可以在应用程序中提供安全通信的一个协议&#xff0c;通过SSH可以安全地进行网络数据传输&#xff0c;它的主要原理是利用非对称加密…

Libhybris之线程局部存储TLS实例(五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

二十三、W5100S/W5500+RP2040树莓派Pico<Web I/O 通过网页控制板载LED灯>

文章目录 1 前言2 简介2 .1 什么是Web&#xff1f;2.2 Web的优点2.3 Web数据交互原理2.4 Web应用场景 3 WIZnet以太网芯片4 HTTP网络设置示例概述以及使用4.1 流程图4.2 准备工作核心4.3 连接方式4.4 主要代码概述4.5 结果演示 5 注意事项6 相关链接 1 前言 Web只是一个静态的文…

电源基础元件

文章目录 电源基础元件理想电压源理想电流源受控电源 电源基础元件 理想电压源 定义 其两端电压总能保持定值或一定的时间函数&#xff0c;其值与流过它的电流i无关的元件叫理想电压源 理想电压源的电压、电流关系 1.电源两端电压由电源本身决定&#xff0c;与外电路无关&…

桶装水订水送水app有哪些功能?

桶装水订水送水app是一款专为送水工量身打造的提供送水服务的软件&#xff0c;在这里&#xff0c;送水人员将更好的在线发布一些送水信息&#xff0c;在线接单等功能&#xff0c;极大的提高了工作效率&#xff0c;方便了日常生活。 系统的商户端&#xff0c;专为送水工日常送水…

【计算机网络】VRRP协议理论和配置

目录 1、VRRP虚拟路由器冗余协议 1.1、协议作用 1.2、名词解释 1.3、简介 1.4、工作原理 1.5、应用实例 2、 VRRP配置 2.1、配置命令 2.2、拓扑与配置&#xff1a; 1、VRRP虚拟路由器冗余协议 1.1、协议作用 虚拟路由冗余协议(Virtual Router Redundancy Protocol&am…

2023nacos源码解读第2集——nacos-server的启动

nacos 是一个典型的server-client中间件&#xff0c;server这里安装最新的nacos-server 2.3.0-BETA版本 1.docker启动nacos-server 镜像详情参考nacos-docker项目的readme &#xff0c;很方便&#xff0c;但是官方提供的nacos-server镜像往往可能滞后&#xff0c;且不便于后续…

【Java 进阶篇】JQuery DOM操作:舞动网页的属性魔法

在前端的舞台上&#xff0c;属性操作是我们与HTML元素进行互动的关键步骤之一。而JQuery&#xff0c;这位前端开发的巫师&#xff0c;通过简洁而强大的语法&#xff0c;为我们提供了便捷的属性操作工具。在这篇博客中&#xff0c;我们将深入研究JQuery DOM操作中的属性操作&…

C语言--1,5,10人民币若干,现在需要18元,一共有多少种?

今天小编给大家分享一下穷举法的一道典型例题 一.题目描述 1,5,10人民币若干,现在需要18元,一共有多少种? 二.思路分析 总共有18块钱&#xff0c;设1元有x张&#xff0c;5元有y张&#xff0c;10元有z张&#xff0c;则有表达式&#xff1a;x5y10z18&#xff0c;穷举法最重要的…

Unity中雾效的实现方法二

文章目录 前言一、声明雾效所需要的内置变体二、在 v2f 中声明顶点传入片段中的雾效插值器三、 在顶点着色器中计算雾效采样四、在片元着色器中进行雾效颜色混合在这里插入图片描述 五、最终效果 前言 Unity中雾效的实现方法二&#xff0c;使用 Unity 自带的方法实现&#xff…

Spring IOC - BeanDefinition解析

1. BeanDefinition的属性 BeanDefinition作为接口定义了属性的get、set方法。这些属性基本定义在其直接实现类AbstractBeanDefinition中&#xff0c;各属性的含义如下表所示&#xff1a; 类型 名称 含义 常量 SCOPE_DEFAULT 默认作用域&#xff1a;单例模式 AUT…

4.CentOS7安装MySQL5.7

CentOS7安装MySQL5.7 2023-11-13 小柴你能看到嘛 哔哩哔哩视频地址 https://www.bilibili.com/video/BV1jz4y1A7LS/?vd_source9ba3044ce322000939a31117d762b441 一.解压 tar -xvf mysql-5.7.26-linux-glibc2.12-x86_64.tar.gz1.在/usr/local解压 tar -xvf mysql-5.7.44-…

22.构造一个关于员工信息的结构体数组,存储十个员工的信息

结构体问题。构造一个关于员工信息的结构体数组&#xff0c;存储十个员工的信息&#xff0c;包括员工工号&#xff0c;员工工资&#xff0c;员工所得税&#xff0c;员工实发工资。要求工号和工资由键盘输入&#xff0c;并计算出员工所得税&#xff08;所得税工资*0.2&#xff0…

微服务概览

单体架构 传统的软件应用为单体架构。尽管也是模块化逻辑&#xff0c;但是最终还是会打包并并部署为单体应用。最主要的原因是太复杂。并且应用扩展性低&#xff0c;可靠性也低。敏捷开发和部署变得无法完成。 治理办法&#xff1a;化繁为简&#xff0c;分而治之。 微服务起源…

JavaScript从入门到精通系列第三十六篇:详解JavaScript中的事件监听和事件响应

文章目录 一&#xff1a;什么叫事件 1&#xff1a;概念 2&#xff1a;处理这个事件 (一)&#xff1a;鼠标单机按钮 (二)&#xff1a;鼠标双机按钮 (三)&#xff1a;鼠标移动 3&#xff1a;写法弊端 4&#xff1a;Dom Event 二&#xff1a;监听事件 1&#xff1a;元素事…