【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++有了解了。
如果你感觉这篇博客对你有帮助,不要忘了一键三连哦

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

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

相关文章

《A data independent approach to generate adversarial patches》论文分享(侵删)

原文链接&#xff1a;A data independent approach to generate adversarial patches | Machine Vision and Applications author{Xingyu Zhou and Zhisong Pan and Yexin Duan and Jin Zhang and Shuaihui Wang}, 一、介绍 在图像识别领域&#xff0c;与数字域中的攻击相比…

【C++杂货铺铺】AVL树

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 概念 &#x1f4c1; 节点的定义 &#x1f4c1; 插入 &#x1f4c1; 旋转 1 . 新节点插入较高左子树的左侧---左左&#xff1a;右单旋 2. 新节点插入较高右子树的右侧---右右&#xff1a;左单旋 3. 新节点插入较高左…

工业级路由器的穿透力是不是更强(原创科普)

今天我想和大家聊聊工业级路由器的一个重要特性——穿透力。作为一名从事工业网络通信的工程师,我发现很多用户在选择工业级路由器时,都会问到一个问题:"工业级路由器的穿透力是不是更强?"下面就让我来为大家解答这个疑问。当然如果有通信产品需要也可以关注星创易联…

Kafka效率篇-提升效率三板斧

kafka在效率上做了很多的努力。最初的一个使用场景是处理网页上活跃的数据&#xff0c;它往往有非常大的体量&#xff0c;每个页面都能产生数十条写入。而且我们假设每条消息都会被至少一个消费者消费&#xff08;通常是多个&#xff09;&#xff0c;因此&#xff0c;我们努力让…

二维费用背包分组背包

二维费用背包&分组背包 一定要做的

真要这么卷?某国产大模型定价下调90%,百万 tokens 只需 1 元!

就在刚刚&#xff0c;国内明星AI公司——智谱AI官宣重磅炸弹&#xff1a; 将能力对标GPT3.5-Turbo的GLM-3的大模型API调用价格最高下调90%&#xff0c;价格仅为原来的十分之一&#xff01; 废话不多说&#xff0c;直接上图&#xff1a; 官网地址&#xff1a;https://open.big…

机器视觉技术精准测量点胶高度与宽度:提升生产质量的新利器

在现代化生产线中&#xff0c;点胶工艺是许多产品制造过程中的重要环节。点胶的高度和宽度直接影响到产品的质量和性能。传统的测量方法往往效率低下、精度不高&#xff0c;而机器视觉技术的引入&#xff0c;为点胶高度和宽度的测量带来了革命性的变革。本文将探讨机器视觉如何…

Linux 操作系统MySQL 数据库1

1.MySQL 数据库 数据库是“按照数据结构来组织、 存储和管理数据的仓库”。 是一个长期存储在计算机内的、 有组织的、 可共享的、 统一管理的大量数据的集合。 它的存储空间很大&#xff0c; 可以存放百万条、 千万条、 上亿条数据。 但是数据库并不是随意地将数据进行…

【Qt 学习笔记】Qt常用控件 | 容器类控件 | Group Box的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 容器类控件 | Group Box的使用及说明 文章编号&#xff…

测试萌新三天速通python基础(二)列表,字符串,元组,字典,遍历,容器,集合,函数

python基础 字符串下标(索引)切片字符串的替换 replace()字符串拆分 split()字符串的连接 join列表 list列表的增删改查列表的反转 reverse()排序列表嵌套元组 tuple 排序 升序降序交换变量字典 dict查询遍历容器集合函数参数函数的嵌套调⽤函数的返回值模块导⼊的⽅法____name…

【FFmpeg】Filter 过滤器 ② ( 裁剪过滤器 Crop Filter | 裁剪过滤器语法 | 裁剪过滤器内置变量 | 裁剪过滤器常用用法 )

文章目录 一、裁剪过滤器1、裁剪过滤器简介2、裁剪过滤器语法3、裁剪过滤器内置变量4、裁剪过滤器示例5、裁剪过滤器应用6、裁剪过滤器图示 二、裁剪过滤器常用用法1、裁剪指定像素的视频区域2、裁剪视频区域中心正方形 - 默认裁剪3、裁剪视频区域中心正方形 - 手动计算4、裁剪…

【Linux】轻量级应用服务器如何开放端口 -- 详解

一、测试端口是否开放 1、测试程序 TCP demo 程序&#xff08;可参考&#xff1a;【Linux 网络】网络编程套接字 -- 详解-CSDN博客&#xff09; 2、测试工具 Windows - cmd 窗口 输入命令&#xff1a;telnet [云服务器的公网ip] [port] 二、腾讯云安全组开放端口 1、安全组设…

【C++】——string类

前言 在C语言里面我们用的字符串都是以\0结尾的字符合集&#xff0c;为了操作方便所以在c中推出了stirng类 一 string介绍 1.string是表示字符串的字符串类 2.因为是类&#xff0c;所以他会有一些常用的接口&#xff0c;同时也添加了专门用来操作string的常规操作 3.string…

揭秘高效引流获客的艺术:转化技巧大公开

在数字化营销的海洋中&#xff0c;每个企业都如同一艘努力航行的船&#xff0c;而流量便是推动船只前行的风帆。如何有效吸引并获取潜在客户&#xff0c;即所谓的“引流获客”&#xff0c;已成为企业市场营销策略中不可或缺的一环。本文将详细探讨几种实用且高效的引流获客技巧…

Ardupilot开源代码之Rover上路 - 后续1

Ardupilot开源代码之Rover上路 - 后续1 1. 源由2. 问题汇总2.1 问题1&#xff1a;飞控选择2.2 问题2&#xff1a;飞控安装位置和固定2.3 问题3&#xff1a;各种插头、插座配套2.4 问题4&#xff1a;分电板缺陷2.5 问题5&#xff1a;电机编码器接线及正反向问题2.6 问题6&#x…

【C++】stack和queue 适配器

&#x1f525;个人主页&#xff1a;北辰水墨 &#x1f525;专栏&#xff1a;C学习仓 本节内容我们来讲解栈和队列的模拟实现&#xff0c;文末会赋上模拟实现的代码 一、stack的使用和模拟实现 stack适配器的介绍&#xff1a; 1. stack是一种容器适配器&#xff0c;专门用在具…

基于openEuler22.03 LTS环境的容器项目实训——分布式微服务项目部署

一、说明 本文配置环境为VMware虚拟机&#xff08;4核CPU&#xff0c;4 GB内存&#xff0c;40GB磁盘&#xff09;&#xff0c;OS为openEuler 22.03 LTS &#xff0c;虚拟机要求能联网。 二、安装docker环境 2.1 安装docker相关软件包 [rootnode01 ~]# dnf -y install docker…

Windows环境下VSCode加MinGw-W64搭建C/C++开发环境

前言&#xff1a; 本文记录了自己在配置 Windows环境下 VSCode&#xff0c;并安装MinGW-W64来搭建windows操作系统下下的C/C开发环境。本文重点参考了如下链接中知乎上的文章里介绍的方法&#xff0c;在windows上安装 MinGW-W64。 vscode c/c环境配置&#xff08;MinGW&…

深度学习中的一些概念

训练术语 欠拟合 欠拟合是指模型没有很好地捕获到数据特性&#xff0c;不能完整地表示数据的全部信息&#xff0c;也就是模型的复杂度低于应有的水平。例如&#xff0c;假设一个数据集实际上服从二阶多项式分布&#xff0c;但我们使用一阶线性模型去拟合它&#xff0c;这样的…

开发时如何快速分析代码和生成测试方法(Baidu Comate插件帮我一键分析)

目录 前言 Baidu Comate智能编码助手简介 安装教程 使用RabbitMQ一个绑定队列方法进行演示 进行测试现有功能 使用感觉 测试结果 前言 因为在开发代码的时候&#xff0c;发现有很多都是废话也不是很想写注释 的&#xff0c;毕竟程序员最讨厌的两件事情&#xff0c;一…