首页 > 编程语言 >C++11——3.17-3.20 右值引用

C++11——3.17-3.20 右值引用

时间:2023-09-04 14:22:26浏览次数:37  
标签:11 右值 int 左值 C++ num 引用 构造函数

★★★原文链接★★★:https://subingwen.cn/cpp/rvalue-reference/

  • 3.17. 右值和右值引用
  • 3.18. 右值引用的作用以及使用
  • 3.19. 未定引用类型的推导
  • 3.20. 右值引用的传递
  • 3.17. 右值和右值引用

左值,lvalue,locator value,(locator:定位器)

右值,rvalue,read value,(read:只读)

右值分为 纯右值 和 将亡值。

右值语法:

int&& a = 10;两个&

能取地址是左值,不能取地址是右值

不能用左值去初始化右值引用,要用右值初始化右值引用

// 左值
int num = 9;	// num是左值
// 左值引用
int& a = num;	// a是左值引用,不占用额外的内存地址,是num的别名
// 右值
// 常量整数,常量字符串等...55, abcd,不能取地址,只能读它的内容
// 右值引用
int&& b = 8;	// ★★★b是右值引用,需要用右值初始化(8)
// int&& b2 = b;	// ★★★报错,不能用 右值引用 初始化 右值引用
// 常量左值引用
const int& c = num;
const int& c2 = b;	// 可以用 右值引用 初始化 常量左值引用
const int& c3 = 1;
const int& c4 = a;
// 常量右值引用
const int&& d = 6;	// 常量右值引用 的初始化也需要用右值(6)

// 常量左值引用 可以使用 常量右值引用 来初始化
const int& e = d;

总结:

常量左值引用 可以用 左值、左值引用、右值、右值引用、常量右值引用 来进行初始化。

 

  • 3.18. 右值引用的作用以及使用

先来看一个例子:

#include <iostream>
using namespace std;

class Test {
public:
	// 默认构造函数
	Test() :m_num(new int(100))
	{
		cout << "construct: my name is jerry" << endl;
		cout << "m_num地址:" << &m_num << endl;
	}
	// 拷贝构造函数
	Test(const Test& a) :m_num(new int(*a.m_num)) 
	{
		cout << "copy construct: my name is tom" << endl;
	}
	// 析构
	~Test() {
		cout << "destruct Test class..." << endl;
		delete m_num;
	}

	int* m_num;
};

Test getObj() {
	Test t;
	return t;
}

int main() {
	Test a = getObj();
	return 0;
}

res:

  

可以看到 a 调用 getObj() 时,先发生了一次默认构造,此时构造的是 getObj() 函数中的 t;然后发生了一次拷贝构造,此时 t 拷贝给 a;getObj() 函数调用完成后析构掉 t,主函数运行结束析构掉 a.

 

给上面的代码加一个 移动构造函数(在 class 内加):

(右值引用构造函数 也称为 移动构造函数)

	// 移动构造函数 作用:★★★复用其他对象中的资源(具体是指其他对象中的 ★★★堆内存)
	// m_num,转移堆内存资源,浅拷贝
	Test(Test&& a):m_num(a.m_num)
	{
		a.m_num = nullptr;	// ★★★因为此对象的 m_num 中存放的地址和 a 对象的 m_num 存放的地址相同,所以 a 对象被析构时 不能让 a.m_num 指向的地址的内存被释放,所以把 a.m_num 置空
		cout << "move construct..." << endl;
	}

res:

  

可以看到 a 调用 getObj() 时,发生了一次默认构造,一次移动构造;

如果类中有移动构造函数,在进行赋值操作时,编译器会判断 = 右边的对象是不是临时对象:

= 右边是临时对象(将亡值):调用移动构造函数;= 右边不是临时对象,调用拷贝构造函数;如果没有移动构造函数,调用拷贝构造函数。

调用 移动构造时,没有进行堆内存资源的申请(拷贝构造函数 有堆内存资源的申请,深拷贝),移动构造函数 实际上进行了一个浅拷贝,实现了 堆内存资源的转移,提高了效率。

 

  • 3.19. 未定引用类型的推导

记住两点即可:

  • 通过右值推导 T&& 或者 auto&& 得到的是一个右值引用类型;
    通过非右值(右值引用、左值、左值引用、常量右值引用、常量左值引用)推导 T&& 或者 auto&& 得到的是一个左值引用类型。
  • const T&& 表示一个右值引用,不是未定引用类型。

 

  • 3.20 右值引用的传递

看一段代码:

#include <iostream>
using namespace std;

void printValue(int &i)
{
    cout << "l-value: " << i << endl;
}

void printValue(int &&i)
{
    cout << "r-value: " << i << endl;
}

void forward(int &&k)
{
    printValue(k);
}

int main()
{
    int i = 520;
    printValue(i);
    printValue(1314);
    forward(250);

    return 0;
}

res:

  

编译器会根据传入的参数的类型(左值还是右值)调用对应的重置函数(printValue),函数forward()接收的是一个右值,但是在这个函数中调用函数printValue()时,参数k变成了一个命名对象,编译器会将其当做左值来处理。

总结:

  • 右值引用类型可能是左值也可能是右值
  • 编译器会将已命名的右值引用视为左值,将未命名的右值引用视为右值

 

★★★原文链接★★★:https://subingwen.cn/cpp/rvalue-reference/

(〃>_<;〃)(〃>_<;〃)(〃>_<;〃)

标签:11,右值,int,左值,C++,num,引用,构造函数
From: https://www.cnblogs.com/wjjgame/p/17675349.html

相关文章

  • Linux 服务器下C++开发找不到mysql.h
    问题背景腾讯云服务器,linuxcentOS7内核,mysql版本5.5为宝塔腾讯云版自动安装C++用cmake编译时找不到mysql.h解决1.首先尝试yum安装mysql-devel包,但是yum让我直接下载了mariadb相关的包,下载时它,与原有包冲突bt-mysql55-5.5.62-1.el7.x86_64,但是删除原有包后mysql启动有问......
  • BUUCTF [CISCN2019 华东南赛区]Web11
    切入点如图:测试模板注入最后或者payload:X-Forwarded-For:{ifreadfile('/flag')}{/if}原理是Smarty已经废弃{php}标签。在Smarty3.1,{php}仅在SmartyBC中可用。Smarty的{if}条件判断和PHP的if非常相似,只是增加了一些特性。每个{if}必须有一个配对的{/if}。全部的PHP条件表......
  • c++ opencv 16bit tiff图像学习笔记
    1、读取图像基本信息:长、宽、通道数、灰度最大值、最小值、均值、方差值和灰度直方图#include<opencv2/opencv.hpp>usingnamespacecv;usingnamespacestd;intmain(intargc,char**argv){//读入图像Matsrc=imread("C:\\Users\\MingYi-LZQ\\Desktop\\1......
  • 使用百度文心一言生成bat代码(查找当前目录所有文件名带11的txt文件并修改为22)
    百度文心一言开放给普通用户了,网址:文心一言请用[bat]编程:查找当前目录所有文件名带11的txt文件并修改为22生成的代码需要简单修改下,主要问题在->位置没有使用转义符会导致echo后面的字符到txt中,思路还是可以的,不错点击查看代码@echooffsetlocalenabledelayedexpansion......
  • c++单例模式总结
    分类懒汉式:实例对象在第一次被使用时才进行初始化。饿汉式:实例在定义时就被初始化。特点1、构造函数和析构函数私有化,不允许外部创建实例对象。2、拷贝构造函数和复制运算符重载被delete,不允许产生新的实例。3、内部定义一个私有的静态数据成员,该成员为本类的实例化对象。4......
  • Acwing.第119场周赛
    可惜这场比赛没打,去操场溜达去了哈哈哈哈比赛链接A字符串还原有一个由小写字母构成的字符串b是通过以下方法生成的:首先,构造一个由小写字母构成的长度不少于2的字符串a。然后,按照从左到右的顺序,将字符串a的所有长度为2的子串拼接在一起,构成字符串b。例如,如果字符串a......
  • c++11关键字
    decltype关键字:查询关键字的数据类型#语法:decltype(expression)var;1)如果expression是没有用括号括起来的标识符(不包括decltype本身的括号,则var的类型与该标识符的类型相同,包括const等限定符,注意如果返回值为引用时需要先初始化2)如果expression是函数调用,则var的类型与......
  • Google C++编程规范(Google C++ Style Guide)
    参考链接:Google代码规范C++总结Google开源项目风格指南——中文版GoogleC++StyleGuide是一份不错的C++编码指南,我制作了一张比较全面的说明图,可以在短时间内快速掌握规范的重点内容。不过规范毕竟是人定的,记得活学活用。看图前别忘了阅读下面两条重要建议:保持一致也......
  • C/C++ const关键字 解读
    Thecollocationbetweenconstandoriginalpointerisconfusedtomanypeople.Therearetwousagesofit.Thefirstoneisavariablepointerthatpointsaconstantdata.i.e.constint*p#include<iostream>intmain(){ inta=1,b=2; const......
  • 「突刺贯穿第二分块」P4117 [Ynoi2018] 五彩斑斓的世界
    很帅气!分块在线转离线,考虑每个块对于询问的贡献。维护块的max和tag分别代表最大值和减了多少。先考虑整块,\(max<2*x:\)每次暴力区间平移即可。否则对于\([1,x]\)全部加上\(x\)平移到\([x+1,x*2]\),然后区间整体减\(x\)即可。散块怎么做?暴力减,然后重构块......