当前位置: 首页 > news >正文

【C++11】列表初始化、右值引用的详细讲解(上)

前言
在一开始学C++之前我们就简单的了解了一下C++的发展历史。

  • 相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率
  • 加了许多特性,约140个新特性。使得C++更像一种新语言,比如:正则表达式、基于范围for循环、auto关键字、新容器、列表初始化、标准线程库等。

C++11官网:链接: C++文档

目录

    • 1.统一的列表初始化
      • 1.1 { } 花括号初始化:
      • 1.2 std::initializer_list :
    • 2.类型自动推导
      • 2.1 Auto
      • 2.2 decltype
    • 3.右值引用
      • 3.1 什么是左值和右值:
      • 3.2 右值引用使用场景和意义:
        • 3.2.1 右值引用之移动构造:
        • 3.2.1 右值引用之移动赋值:
    • 4.新的类功能
    • 5. C++11 新的关键字
      • 5.1 强制生成默认函数的关键字default
      • 5.2 禁止生成默认函数的关键字delete:

1.统一的列表初始化

1.1 { } 花括号初始化:

在C++98中,标准允许使用花括号{} 对数组 或者 结构体元素 进行统一的列表初始值设定:

struct Point
{
int _x;
int _y;
};
int main()
{
% 数组
int array1[] = { 1, 2, 3, 4, 5 };
int array2[5] = { 0 };
% 结构体
Point p = { 1, 2 };
return 0;
}

C++11 扩大了用大括号括起的列表初始化 的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用列表初始化时,可添加等号(=),也可不添加。


int main()
{Date d1(2022, 1, 1); // old style// C++11支持的列表初始化,这里会调用构造函数初始化Date d2{ 2022, 1, 2 };Date d3 = { 2022, 1, 3 };
}

1.2 std::initializer_list :

链接: std::initializer_list的介绍文档:
在这里插入图片描述

  • std::initializer_list是个类模板
  • std::initializer_list, 为了让容器的初始化进行统一

我们先来看一下其类型:

在这里插入图片描述

  • std::initializer_list支持迭代器

注意:

  • std::initializer_list内容是不能被改的

> 为什么突然要加到一个容器了呢?

首先std::initializer_list是C++11新提出来的
其次有了std::initializer_list,之前学的容器也都支持了用{ }列表初始化
底层都是增加了一个支持std::initializer_list的构造函数

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

Vector支持initializer_list的举例:

先构造一个initializer_list再用initializer_list构造一个vector,具体过程:

在这里插入图片描述

  • 可以和之前隐式类型转换联系起来,
  • 也是中间产生了一个临时对象(initializer_list),再用临时对象去拷贝构造。

2.类型自动推导

2.1 Auto

C++11中废弃auto原来的用法,将其用于实现自动类型推导。

auto it = dict.begin();
  • 尾置类型通常要和auto结合使用。
  • auto必须要进行初始化,因为是通过初始化的类型来推导的。

2.2 decltype

关键字decltype将变量的类型声明为表达式指定的类型.

decltype(x * y) ret; // ret的类型是double
decltype(&x) p;
  • decltype可以不需要初始化,方便了很多。(函数,表达式)
  • decltype推导表达式类型是在编译期完成的,并且不会真正计算表达式的值

3.右值引用

3.1 什么是左值和右值:

C++11中新增了的右值引用语法特性。

1. 什么是左值?

  • 左值是一个表示数据的表达式,如:变量名或解引用的指针
  • 左值可以取地址+ 一般情况下可以修改(const修饰的左值,不能被修改)
  • 左值可以出现赋值符号的左边,也可以出现在右边
  • 定义时 const修饰后的左值,不能给它赋值,但是可以取它的地址。
  • 左值引用就是给左值的引用,给左值取别名
int main()
{
// 以下的p、b、c、*p都是左值int* p = new int(0);int b = 1;const int c = 2;
// 以下几个是对上面左值的左值引用int*& rp = p;int& rb = b;const int& rc = c;int& pvalue = *p;return 0;
}

2. 什么是右值?

  • 右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等
  • 右值不能取地址
  • 右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边
  • 右值引用就是对右值的引用,给右值取别名
  • 使用&& 来声明。
int main()
{
double x = 1.1, y = 2.2;
// 以下几个都是常见的右值
10;
x + y;
fmin(x, y); ---函数返回值
// 以下几个都是对右值的右值引用
int&& rr1 = 10;
double&& rr2 = x + y;
double&& rr3 = fmin(x, y);
}

> C++11有对右值进行了严格的区分:

纯右值: 比如常量,表达式值a+b 内置类型右值
将亡值:比如函数传值返回,表达式的中间结果。顾名思义,将亡值的空间马上就要被释放了。

右值引用的特殊情况1-----:

  • 右值是不能取地址的,但是给右值取别名后,会导致右值被存储到特定位置,且可以取到该位置的地址
  • 例如:不能取字面量10的地址,但是rr1引用后,可以对rr1取地址,也可以修改rr1 (rr1就变成左值)。如果不想rr1被修改,可以用const int&& rr1 去引用。
  • Const Int && 右值引用 使用场景需要注意
int main()
{
double x = 1.1, y = 2.2;
int&& rr1 = 10;
const double&& rr2 = x + y;
}

右值引用的特殊情况2 ------const左值引用:

  • const引用:可以引用普通左值、const左值、右值,但不能修改const引用的值。
    const int& b = a;//const引用,引用普通左值const int& c = ca;//const引用,引用const左值const int& d = 30;//const引用,引用右值

总结:

  • 左值引用只能引用左值,不能引用右值
  • const左值引用既可以引用 左值,又可以引用右值
  • 右值引用只能右值,不能引用左值
  • 但是右值引用可以move以后的左值

3.2 右值引用使用场景和意义:

左值引用的使用场景

  • 做参数
  • 做返回值都可以提高效率

左值引用的短板

  • 当函数返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回,只能传值返回。
  • 例如:bit::string to_string(int value) 、Date operator++(int)
    函数中可以看到,这里只能使用传值返回,传值返回会导致至少1次拷贝构造(如果是一些旧一点的编译器可能是两次拷贝构造)

提出解决方案

  • C++11引入了移动构造和移动赋值函数

  • 根据函数匹配规则,会更匹配移动构造和移动赋值函数。

// 注意:this指向的对象函数结束后不会销毁,故以引用方式返回提高效率
Date& operator++()
{
_day += 1;
return *this;
}//下面temp是临时对象,因此只能以值的方式返回,不能返回引用
Date operator++(int) --传值返回
{
Date temp(*this);
_day += 1;
return temp;
}

在这里插入图片描述

3.2.1 右值引用之移动构造:

右值引用和移动语义解决上述问题:
在bit::string中增加移动构造,移动构造本质是将参数右值的资源窃取过来,占位已有,那么就不用做深拷贝了,所以它叫做移动构造,就是窃取别人的资源来构造自己

// 移动构造
string(string&& s)
:_str(nullptr)
,_size(0)
,_capacity(0)
{
cout << "string(string&& s) -- 移动语义" << endl;
swap(s);
}
int main()
{
bit::string ret2 = bit::to_string(-1234);
return 0;
}

这里没有调用深拷贝的拷贝构造,而是调用了移动构造,移动构造中没有新开空间,拷贝数据,所以效率提高了。。

在这里插入图片描述
编译器匹配。。

3.2.1 右值引用之移动赋值:

在bit::string类中增加移动赋值函数,再去调用bit::to_string(1234),不过这次是将 bit::to_string(1234)返回的右值对象赋值给ret1对象,这时调用的是移动构造。

// 移动赋值
string& operator=(string&& s)
{
cout << "string& operator=(string&& s) -- 移动语义" << endl;
swap(s);
return *this;
}
int main()
{
bit::string ret1;
ret1 = bit::to_string(1234);
return 0;
}

4.新的类功能

默认成员函数:
原来C++类中,有6个默认成员函数:

  • 构造函数
  • 析构函数
  • 拷贝构造函数
  • 拷贝赋值重载
  • 取地址重载
  • const 取地址重载

C++11 新增了两个默认成员函数:

- 移动构造函数
- 移动赋值

移动构造和移动赋值是有条件的,并且默认生成的达到不了我们想要的效果,
所以一般我们自己实现

  • 如果你没有自己实现移动构造函数,且没有实现析构函数
    、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造。
  • 如果你没有自己实现移动赋值重载函数,且没有实现析构函数
    、拷贝构造、拷贝赋值重载中的任意一个,那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造完全类似)
  • 如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。

STL容器中的各种插入也用到了右值引用:==

当这些容器的元素是某个对象的时候,插入的话要new一个新的元素,也会产生深拷贝的问题,所以这里用到右值引用将会非常方便

在这里插入图片描述

5. C++11 新的关键字

5.1 强制生成默认函数的关键字default

C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原因这个函数没有默认生成。
比如:我们提供了拷贝构造,就不会生成移动构造了,那么我们可以
使用default关键字显示指定移动构造生成

class Person
{
public:
Person(const char* name = "", int age = 0)
:_name(name)
, _age(age)
{}
Person(const Person& p)
:_name(p._name)
,_age(p._age)
{}
Person(Person&& p) = default;
private:
bit::string _name;
int _age;
};

5.2 禁止生成默认函数的关键字delete:

如果能想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且只声明补丁已,这样只要其他人想要调用就会报错。
在C++11中更简单,只需在该函数声明加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数。

class Person
{
public:
Person(const char* name = "", int age = 0)
:_name(name)
, _age(age)
{}
Person(const Person& p) = delete;
private:
bit::string _name;
int _age;
};

尾声
看到这里,相信大家对这个C++有了解了。
如果你感觉这篇博客对你有帮助,不要忘了一键三连哦

相关文章:

【C++11】列表初始化、右值引用的详细讲解(上)

前言 在一开始学C之前我们就简单的了解了一下C的发展历史。 相比较而言&#xff0c;C11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全&#xff0c;不仅功能更强大&#xff0c;而且能提升程序员的开发效率加了许多特性&#xff0c;约140个新特性。使得C…...

【JAVA进阶篇教学】第十三篇:Java中volatile关键字讲解

博主打算从0-1讲解下java进阶篇教学&#xff0c;今天教学第十三篇&#xff1a;volatile关键字讲解。 在 Java 中&#xff0c;volatile关键字是一种轻量级的同步机制&#xff0c;用于确保变量的可见性和禁止指令重排序。本文将详细解释volatile关键字的工作原理、可见性保证以及…...

蓝桥杯-地宫取宝

X 国王有一个地宫宝库&#xff0c;是 nm 个格子的矩阵&#xff0c;每个格子放一件宝贝&#xff0c;每个宝贝贴着价值标签。 地宫的入口在左上角&#xff0c;出口在右下角。 小明被带到地宫的入口&#xff0c;国王要求他只能向右或向下行走。 走过某个格子时&#xff0c;如果那个…...

带头单链表 C++实现

节点定义 带头单链表&#xff1a;我们只需要一个结点指针指向整个链表的第一个节点&#xff0c;这样我们就可以通过next指针访问整个链表内的所有节点 template<class T> struct ListNode {T _val;ListNode* _next;ListNode(const T &val):_val(val),_next(nullptr){…...

学习c#第24天 枚举类型

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace enumType { //定义枚举 public enum Week { 星期一, 星期二, 星期三, 星期四, 星期…...

TensorFlow运行bug汇总

1、ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1 解决方案 pip install urllib31.26.15 -i https://pypi.tuna.tsinghua.edu.cn/simple 升级或者降级 (TF2.1) C:\Users\Administrator>pip install urllib31.26.15 -i https://pypi.tuna.tsinghua.edu.cn/sim…...

docker部署调度程序

Dockerfile(构建初始镜像) # python:3.8-slim-buster为精简版的python FROM python:3.8-slim-buster # 1059为组的id,newgroup为组名,1088为用户的id,newuser为新用户 RUN groupadd -g 1059 newgroup && \useradd -g -u 1088 -g newgroup -m newuser USER newuser RUN…...

websocket和http协议的区别

ws(websocket)协议和http协议是两种不同的协议。 http&#xff1a;http是一种用于传输超文本的应用层协议&#xff0c;通常用于web端浏览器和web端服务器之间传输数据。http也是基于tcp的&#xff0c;但是HTTP只能在同一时刻单向发送消息&#xff0c;是一种半双工通信。&#…...

CSS之定位

目录 CSS定位为什么需要定位定位组成定位的叠放顺序拓展 CSS定位 为什么需要定位 浮动可以让多个块级盒子一行没有缝隙排列显示&#xff0c;经常用于横向排列盒子定位则是可以让盒子自由的在某个盒子内移动位置或者固定屏幕中的某个位置&#xff0c;并且可以压住其他盒子 定…...

[IM002][Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序

解决办法&#xff1a; 安装驱动 下载 ODBC Driver for SQL Server - ODBC Driver for SQL Server | Microsoft Learn...

神经网络复习--神经网络算法模型及BP算法

文章目录 神经网络模型的构成BP神经网络 神经网络模型的构成 三种表示方式&#xff1a; 神经网络的三要素&#xff1a; 具有突触或连接&#xff0c;用权重表示神经元的连接强度具有时空整合功能的输入信号累加器激励函数用于限制神经网络的输出 感知神经网络 BP神经网络 …...

【Java】/*方法的使用-快速总结*/

目录 一、什么是方法 二、方法的定义 三、实参和形参的关系 四、方法重载 五、方法签名 一、什么是方法 Java中的方法可以理解为C语言中的函数&#xff0c;只是换了个名称而已。 二、方法的定义 1. 语法格式&#xff1a; public static 返回类型 方法名 (形参列表) { //方…...

kotlin中协程相关

协程 用同步的方式写出异步的效果协程最重要的是通过非阻塞挂起和恢复实现了异步代码的同步编写方式挂起函数(suspend)不一定就是在子线程中执行的&#xff0c;但是通常在定义挂起函数时都会为它指定其他线程&#xff0c;这样挂起才有意义解决多层嵌套回调 协程不是线程&…...

(自适应手机端)物流运输快递仓储网站模板 - 带三级栏目

(自适应手机端)物流运输快递仓储网站模板 - 带三级栏目PbootCMS内核开发的网站模板&#xff0c;该模板适用于物流运输网站、仓储货运网站等企业&#xff0c;当然其他行业也可以做&#xff0c;只需要把文字图片换成其他行业的即可&#xff1b;自适应手机端&#xff0c;同一个后台…...

Navicat导出表结构到Excel或Word

文章目录 sql语句复制到excel复制到Word sql语句 SELECTcols.COLUMN_NAME AS 字段,cols.COLUMN_TYPE AS 数据类型,IF(pks.CONSTRAINT_TYPE PRIMARY KEY, YES, NO) AS 是否为主键,IF(idxs.INDEX_NAME IS NOT NULL, YES, NO) AS 是否为索引,cols.IS_NULLABLE AS 是否为空,cols.…...

Golang编译优化——稀疏条件常量传播

文章目录 一、概述二、稀疏条件常量传播2.1 初始化worklist2.2 构建def-use链2.3 更新值的lattice2.4 传播constant值2.5 替换no-constant值 一、概述 常量传播&#xff08;constant propagation&#xff09;是一种转换&#xff0c;对于给定的关于某个变量 x x x和一个常量 c …...

人工智能培训讲师咨询叶梓介绍及智能医疗技术与ChatGPT临床应用三日深度培训提纲

1、授课老师简介 叶梓&#xff0c;上海交通大学计算机专业博士毕业&#xff0c;高级工程师。主研方向&#xff1a;数据挖掘、机器学习、人工智能。历任国内知名上市IT企业的AI技术总监、资深技术专家&#xff0c;市级行业大数据平台技术负责人。 长期负责城市信息化智能平台的…...

HCIP(BGP综合实验)--8

一&#xff1a;实验要求 二&#xff1a;实现过程 &#xff08;一&#xff09;配置IP地址&#xff1a; AR1: [AR1]int g0/0/0 [AR1-GigabitEthernet0/0/0]ip add 12.1.1.1 24 [AR1-GigabitEthernet0/0/0]int l0 [AR1-LoopBack0]ip add 172.16.0.1 32 [AR1-LoopBack0]int l1 […...

深入理解C++中的Vector容器:用容器构建高效程序

文章目录 vector介绍vector常用的成员函数有关vector定义的函数vector的迭代器使用vector关于空间操作的成员函数vector的增删查改 总结 vector介绍 在C语言的库中包含有公共数据结构的实现&#xff0c;C的这个部分内容就是众所周知的STL&#xff08;标准模版库&#xff09;&a…...

目标检测YOLO实战应用案例100讲-基于深度学习的交通场景多尺度目标检测算法研究与应用(下)

目录 3.2 基于空洞卷积的特征融合模块设计 3.3 改进k-means聚类算法的anchor尺寸优化设计...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

Git常用命令完全指南:从入门到精通

Git常用命令完全指南&#xff1a;从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...