C++系统研发工程师知识储备(七)

本文详细介绍了C++11的新特性,包括auto关键字、nullptr、智能指针(如std::shared_ptr)、右值引用的概念及应用,以及在多线程中的atomic原子操作。此外,还提到了C++11引入的STL新容器array和tuple。

C++11

(一)C++11有哪些新特性?

1、 auto关键字

  • 编译器可以根据初始值自动推导出类型。但是不能用于函数传参以及数组类型的推导

2、 nullptr关键字

  • nullptr是一种特殊类型的字面值,它可以被转换成任意其它的指针类型;而NULL一般被宏定义为0,在遇到重载时可能会出现问题

3、智能指针

C++11新增了std::shared_ptr、std::weak_ptr等类型的智能指针,用于解决内存管理的问题

4、初始化列表:使用初始化列表来对类进行初始化

5、右值引用

基于右值引用可以实现移动语义和完美转发,消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率

(1)左值与左值引用
  • 左值,就是在内存有确定存储地址、有变量名,表达式结束依然存在的值。
  • 左值可以分为两类:非常量左值和常量左值;同理,右值也可以分为两类:非常量右值和常量左值。
  • 左值引用,就是绑定到左值的引用,通过&来获得左值引用。
  • 非常量左值引用只能绑定到非常量左值上;常量左值引用可以绑定到非常量左值、常量左值、非常量右值、常量右值等所有的值类型
(2) 右值与右值引用
  • 右值,就是在内存没有确定存储地址、没有变量名,表达式结束就会销毁的值。
  • 右值引用,就是绑定到右值的引用,通过&&来获得右值引用。
  • 非常量右值引用只能绑定到非常量右值上;常量右值引用可以绑定到非常量右值、常量右值上
(3) 右值引用与左值引用的区别
  • 左值可以寻址,而右值不可以。
  • 左值可以被赋值,右值不可以被赋值,可以用来给左值赋值。
  • 左值可变,右值不可变(仅对基础类型适用,用户自定义类型右值引用可以通过成员函数改变)
  • 左值引用绑定到有确定存储空间以及变量名的对象上,表达式结束后对象依然存在;
  • 右值引用绑定到要求转换的表达式、字面常量、返回右值的表达式等临时对象上,赋值表达式结束后就对象就会被销毁。
  • 左值引用后可以利用别名修改左值对象;右值引用绑定的值不能修改。
  • 右值引用是C++11中引入的新特性 , 它实现了转移语义和精确传递。它的主要目的有两个方面:
    • 消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率。
    • 能够更简洁明确地定义泛型函数。
(4) 引入右值引用的原因
  • 替代需要销毁对象的拷贝,提高效率
    • 某些情况下,需要拷贝一个对象然后将其销毁,如:临时类对象的拷贝就要先将旧内存的资源拷贝到新内存,然后释放旧内存,引入右值引用后,就可以让新对象直接使用旧内存并且销毁原对象,这样就减少了内存和运算资源的使用,从而提高了运行效率;
  • 移动含有不能共享资源的类对象
    • 像IO、unique_ptr这样的类包含不能被共享的资源(如:IO缓冲、指针),因此,这些类对象不能拷贝但可以移动。这种情况,需要先调用std::move将左值强制转换为右值,再进行右值引用。

6、atomic原子操作用于多线程资源互斥操作

7、 新增STL容器array以及tuple

(二)C++11中的可变参数模板、右值引用和lambda这几个新特性。

1、 可变参数模板

  • C++11的可变参数模板,对参数进行了高度泛化,可以表示任意数目、任意类型的参数,其语法为:在class或typename后面带上省略号”。

2、 右值引用

  • C++中,左值通常指可以取地址,有名字的值就是左值,而不能取地址,没有名字的就是右值。
  • 而在指C++11中,右值是由两个概念构成,将亡值和纯右值。
    • 纯右值是用于识别临时变量和一些不跟对象关联的值,比如1+3产生的临时变量值、true等
    • 将亡值通常是指具有转移语义的对象,比如返回右值引用T&&的函数返回值等。基于右值引用可以实现转移语义和完美转发新特性。
      • 移动语义:对于一个包含指针成员变量的类,由于编译器默认的拷贝构造函数都是浅拷贝,所有我们一般需要通过实现深拷贝的拷贝构造函数,为指针成员分配新的内存并进行内容拷贝,从而避免悬挂指针的问题。
      • 完美转发:完美转发是指在函数模板中,完全依照模板的参数的类型,将参数传递给函数模板中调用的另一个函数,即传入转发函数的是左值对象,目标函数就能获得左值对象,转发函数是右值对象,目标函数就能获得右值对象,而不产生额外的开销。
      • Lambda表达式:Lambda表达式定义一个匿名函数,并且可以捕获一定范围内的变量。Lambda表达式与普通函数最大的区别就是其可以通过捕获列表访问一些上下文中的数据。Lambda的类型被定义为“闭包”的类,其通常用于STL库中,在某些场景下可用于简化仿函数的使用,同时Lambda作为局部函数,也会提高复杂代码的开发加速,轻松在函数内重用代码,无须费心设计接口。

(三)可调用对象(Callable Objects)。

  • c++11中有一个重要的概念叫做可调用对象(Callable Objects)。
  • 可调用对象用处广泛
    • 比如在使用一些基于范围的模板函数时(如 sort()、all_of()、find_if() 等),常常需要我们传入一个可调用对象,以指明我们需要对范围中的每个元素进行怎样的处理
    • 又比如,在处理一些回调函数、触发函数时,也常常会使用可调用对象。
  • 总的来说,可调用对象可以是以下几种情况:

1、普通函数

在这里插入图片描述

2、 函数指针

在这里插入图片描述

3、 仿函数,即重载了operator()运算符的类对象

在这里插入图片描述
在这里插入图片描述

4、 匿名函数,即Lambda表达式(可以在函数内部定义)

(1) 定义形式
	 [captures] (params) -> return_type { statments;} 
  • [captures]为捕获列表,用于捕获外层变量。[&]表示捕获当前范围内所有局部变量。
  • (params)为匿名函数参数列表;当匿名函数没有参数时,可以省略(params)部分
  • -> return_type指定匿名函数返回值类型;当匿名函数体的返回值只有一个类型或者返回值为void时,可以省略->return_type部分
  • { statments; }部分为函数体,包括一系列语句
(2) 例子

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

(3) 隐式捕获
  • 接在函数体内使用我们需要使用的辅助变量而不用在捕获列表中声明,但需要指出捕获方式——值捕获 or 引用捕获。
  • 编译器会把我们写的lambda表达式翻译成一个类,并重载 operator()来实现。
    在这里插入图片描述
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值