c++11右值引用

OneNet平台MQTT连接避坑指南:C语言Token计算实战(附完整代码) 本文详细解析了OneNet平台MQTT连接中的Token计算机制,提供了C语言实现的完整代码和实战指南。通过HMAC算法和Base64编码,开发者可以高效生成安全凭证,避免常见连接问题,适用于物联网设备开发。 阅读详情

c++11中引入了右值引用和移动语义,可以避免无谓的复制,提高了程序的性能。
我们平常所说的引用通常是指左值引用,用&表示。而右值引用,用&&表示。
要介绍右值引用的作用以及如何使用之前,我们必须要搞明白什么是左值,什么是右值。


左值与右值

左值:指表达式结束后依然存在的持久对象。
右值:指表达式结束时就不再存在的临时对象。

一个区分左值与右值的便捷方法:

看看能不能对表达式取地址,如果能,则为左值,否则为右值。
所有的具名变量或对象都是左值,而右值不具名。

举例:

 int a = 10;
 int b = 20;
 int *pFlag = &a;
 vector<int> vctTemp;
 vctTemp.push_back(100);
 string str1 = string("hello");
 string str2 = "world";
 const int &m = 1;

请问,a,b, a+b, a++, ++a, pFlag, *pFlag, vctTemp[0], 100, string(“hello”), str1, str1+str2, m分别是左值还是右值?

a和b都是持久对象(可以对其取地址),是左值;
a+b是临时对象(不可以对其取地址),是右值;
a++是先取出持久对象a的一份拷贝,再使持久对象a的值加1,最后返回那份拷贝,而那份拷贝是临时对象(不可以对其取地址),故其是右值;
++a则是使持久对象a的值加1,并返回那个持久对象a本身(可以对其取地址),故其是左值;
pFlag和*pFlag都是持久对象(可以对其取地址),是左值;
vctTemp[0]调用了重载的[]操作符,而[]操作符返回的是一个int &,为持久对象(可以对其取地址),是左值;
100和string(“hello”)是临时对象(不可以对其取地址),是右值;
str1是持久对象(可以对其取地址),是左值;
str1+str2是调用了+操作符,而+操作符返回的是一个string(不可以对其取地址),故其为右值;
m是一个常量引用,引用到一个右值,但引用本身是一个持久对象(可以对其取地址),为左值


右值引用

右值引用就是一个对右值进行引用的类型。
无论声明左值引用还是右值引用都必须立即进行初始化,因为引用类型本身并不拥有所绑定对象的内存,只是该对象的一个别名。

举例:

int i=42;
int &r=i;   //正确:r引用i
int &&rr=i;   //错误:不能将一个右值引用绑定到一个左值上
int &r2=i*42;    //错误:i*42是一个右值
const int &r3=i*42;     //正确:我们可以将一个const的左值引用绑定到一个右值上
int &&rr2=i*42;         //正确:将rr2绑定到乘法结果上

说明:

  • 返回左值引用的函数,连同赋值,下标,解引用和前置递增/递减运算符,都是返回左值的表达式的例子。我们可以将一个左值引用绑定到这类表达式的结果上。
  • 返回非引用类型的函数,连同算数,关系,位以及后置递增/递减运算符,都生成右值。我们不能将一个左值引用绑定到这类表达式上,但我们可以将一个const的左值引用或者一个右值引用绑定到这类表达式上。


右值引用的作用

通过右值引用的定义,我们可以知道,右值引用只能绑定到一个将要销毁的对象。我们可以通过右值引用的声明,使该右值又“重获新生”,其生命周期与右值引用类型变量的生命周期一样,只要该变量还活着,该右值临时量将会一直存活下去。这样,我们可以通过该右值引用继续使用该右值的数据。

看一下下面的代码:

#include<iostream>
using namespace std;

int g_constructCount=0;
int g_copyConstructCount=0;
int g_destructCount=0;

struct A
{
    A(){
        cout<<"construct: "<<++g_constructCount<<endl;
    }

    A(const A& a)
    {
        cout<<"copy construct: "<<++g_copyConstructCount<<endl;
    }
    ~A()
    {
        cout<<"destruct: "<<++g_destructCount<<endl;
    }
};

A GetA()
{
    return A();
}

int main()
{
   A a=GetA();
   return 0;
}

为了清楚地观察临界值,在GCC下编译时设置编译选项-fno-elide-constructors来关闭返回值优化结果(返回值优化将会把临时对象优化掉)。

运行结果:

construct: 1
copy construct: 1
destruct: 1
copy construct: 2
destruct: 2
destruct: 3

从上面例子中可以看到,在没有返回值优化的情况下,拷贝构造函数调用了两次,一次是GeTA()函数内部创建的对象返回后构造一个临时对象产生的,另一次是在main函数中构造a对象产生的。第二次的destruct是因为临时对象在构造a对象之后就摧毁了。

上述例子中,在main函数中创建了一个类A的对象a,并将GetA()返回的临时对象拷贝给a。如果在上面的代码中我们通过右值引用来绑定函数的返回值,结果又会怎么样呢?

#include<iostream>
using namespace std;

int g_constructCount=0;
int g_copyConstructCount=0;
int g_destructCount=0;

struct A
{
    A(){
        cout<<"construct: "<<++g_constructCount<<endl;
    }

    A(const A& a)
    {
        cout<<"copy construct: "<<++g_copyConstructCount<<endl;
    }
    ~A()
    {
        cout<<"destruct: "<<++g_destructCount<<endl;
    }
};

A GetA()
{
    return A();
}

int main()
{
   const A &&a=GetA();
   return 0;
}

gcc file.c -fno-elide-constructors 运行结果如下:

construct: 1
copy construct: 1
destruct: 1
destruct: 2

我们会发现,通过右值引用,比之前少了一次拷贝构造函数和一次析构函数,原因在于右值引用绑定了右值,让临时右值的生命周期延长了。我们可以利用这个特点做一些性能优化,即避免临时对象的拷贝构造和析构。事实上,通过常量左值引用也经常用来做性能优化。将上面的代码改成:const A&a=GetA();
输出结果与右值引用一样,因为常量左值引用是一个“万能”的引用类型,既可以接受非常量左值,常量左值,又可以接受非常量右值,常量右值。


特例:自动类型推断时的引用折叠

当在发生自动类型推断时(如函数模板的类型自动推导,或auto关键字),T&&并不一定表示右值,它绑定的类型是未定的,既可能是左值又可能是右值。
看看下面的例子:

template<class T>
void f(T&& param);

f(10);    //10是右值
int x=10;
f(x);    //x虽然是左值,但是正确

从上面的例子可以看出,param有时是左值,有时是右值。这表示param实际上是一个未定的引用类型,它是左值还是右值引用取决于它的初始化,如果T&&被一个左值初始化,它就是一个左值;如果它被一个右值初始化,它就是一个右值。
当我们将10传入f函数时,因为10是int类型右值,所以T会被推导为int。
而当我们将左值x对象传入f函数时,T会被推导为int&类型,此时函数参数为int & &&param,此时就涉及到引用折叠,int& &&等价于int&类型。

引用折叠:

  • 所有的右值引用叠加到右值引用上仍然还是一个右值引用。(例:T&& &&折叠成T&&)
  • 所有的其他引用类型之间的折叠都将变成左值引用。 (例:T& &&折叠成T&)

需要我们注意的是,未定的引用类型只在T&&下发生,任何一点附加条件都会使之失效,而变成一个普通的右值引用。
比如:

template<class T>
void f(const T&&param);
int x=10;
f(x);    //错误,此时param是一个右值引用,x为左值,无法传给param


std::move

通过上面的介绍,我们先看一下下面的代码:

int w1,w2;
auto&& v1=w1;  //v1被推导为int&类型
decltype(w1)&& v2=w2;  //错误

v1是一个未定的引用类型,它被一个左值初始化,所以它最终是一个左值;v2是一个右值引用类型,但它被一个左值初始化,一个左值初始化一个右值引用类型是不合法的,所以编译器会报错。
但是,如果我们希望把一个左值赋给一个右值引用类型该怎么做呢?
此时就用到了标准库move函数。

decltype(w1)&& v2=sstd::move(w2);   //正确

虽然我们不能将一个右值引用直接绑定到一个左值上,但我们可以显示地将一个左值转换为对应的右值引用类型。我们可以通过调用一个名为move的新标准库函数来获得绑定到左值上的右值引用。

我们知道,右值表示的是一个临时对象或即将被摧毁的对象,当我们调用move函数返回一个左值对象的右值引用类型时,就意味着承诺:除了对该对象赋值或摧毁它外,我们将不再使用它。我们不能对调用move后的对象的值做任何假设。

Agent 团队管理手册:如何设定目标、分配角色与解决冲突 本文从Agent团队的底层逻辑出发,完整讲解了Agent团队管理的三大核心模块:目标设定(分层拆解+对齐校验)、角色分配(能力匹配+最优算法)、冲突处理(分类处理+仲裁投票),并提供了可直接运行的完整代码示例。通过本文的方法,你可以快速搭建一个高效协作的Agent团队,大幅提升复杂任务的完成效率和准确率。Agent团队是未来AI应用的核心形态,现在正是落地的黄金期,建议你从一个小场景开始动手实践,逐步优化自己的Agent团队管理方法论。 阅读详情

相关推荐

从S参数到SPICE模型:Cadence Sigrity Boardband SPICE完整使用指南

本文详细介绍了Cadence Sigrity Boardband SPICE工具的核心价值与完整使用流程。该工具通过矢量拟合算法,将复杂的多端口S参数文件转化为无源、紧凑且高精度的SPICE等效电路模型,从而极大提升时域仿真效率。指南涵盖了从数据导入、关键参数配置、模型精度验证到集成应用于PowerSI等系统级仿真的全步骤,是信号与电源完整性分析的必备利器。

defi6farmer的博客 432

C++ 右值引用

C++

qwert55kai的博客 3261

TCN(Temporal Convolutional Networks)时序卷积网络详解及代码

TCN(Temporal Convolutional Networks)时序卷积网络详解及代码

zhulewen的博客 7883

c++11特性

转义字符1. \n换行(把字符转换为有特殊含义的字符)\t制表符2.把特殊含义的字符转换为普通字符 windows中\表示路径 转义为一个反斜杠linux系统中路径使用 /来表示 eg:/rootR"xxx()xxx" xxx要相等,作用等于注释原始字面量R可以直接表示字符串的实际含义,不会做链接转义等操作。

weixin_46430763的博客 313

Ubuntu16.04下禁用scp、sftp和winscp

在上一篇博文《Ubuntu16.04 搭建FTP服务器,设置用户权限为只许上传、禁止下载和删除》中,我讲述了Ubuntu16.04下配置FTP,并且设定用户权限为只能上传数据,禁止下载和删除数据。这算在FTP层面封堵了服务器数据泄露的途径。 但是,Ubuntu系统的scp和sftp还是起作用的,理论上只要能用本地机器ping通服务器,就可以用scp和sftp下载数据,这还是存在数据泄露可能的,所...

HPC&Geophysics攻城狮 5735

UBUNTU使用RTL8811CU网卡(包含树莓派)

下载驱动 从绿联中下载:链接 下载解压后,chmod Linux文件夹 sudo chmod -R 777 ./Linux/ 修改系统的BOOT Secure为disable,参考链接:链接 sudo apt install mokutil sudo mokutil --disable-validation 重启电脑后,按照提示选择change secure boot state,并输入对应的字母(并不是全部密码,而是第几个),选择disable即可 进入Linux文件夹,运行命令 ..

Hot_Ant的博客 6246

C++11---右值引用(深度讲解)

左值是一个数据的表达式(例如变量或者解引用后的指针),我们可以对其进行取地址和修改赋值,左值可以出现在赋值符号的左边,而右值不能出现在赋值符号的左边,而左值引用就是对左值起别名,如图1. 左值引用只能引用左值,不能引用右值。2. 但是const左值引用既可引用左值,也可引用右值1. 右值引用只能右值,不能引用左值。2. 但是右值引用可以move以后的左值。

2303_78660611的博客 3010

Unity 游戏实例开发集合 之 Car Racing 2D (2D赛车) 休闲小游戏快速实现

Unity 游戏实例开发集合 之 Car Racing 2D (2D赛车) 休闲小游戏快速实现 目录 Unity 游戏实例开发集合 之 Car Racing 2D (2D赛车) 休闲小游戏快速实现 一、简单介绍 二、Car Racing 2D (2D赛车) 游戏内容与操作 三、相关说明 四、游戏代码框架 五、知识点 六、游戏效果预览 七、实现步骤 八、工程源码地址 九、延伸扩展 一、简单介绍 Unity 游戏实例开发集合,使用简单易懂的方式,讲解常见游戏的开发实现过程,方便

仙魁XAN 7701

【C++】C++11之右值引用

C++11 右值引用 移动构造 移动赋值 移动语义 forward 完美转发 可变参数模板 Args... emplace_back

xiaomage1213888的博客 764

基于STM32F103C8T6的智能蓝牙手环系统设计与实现

摘要:本文设计并实现了一款基于STM32F103C8T6单片机的智能蓝牙手环系统。该系统集成了ADXL345加速度计、DS18B20温度传感器、plusesennor心率模块和BT06蓝牙模块,实现了心率(±2bpm)、体温(±0.5℃)、步数(±3%)等健康数据的实时监测与显示。通过OLED屏提供人机交互界面,支持蓝牙APP远程控制,具备自动步数清零、异常提醒等功能。测试表明系统各项功能均达到设计要求,响应时间0.1-0.5秒,心率检测准确率98%,体温检测准确率99%,功耗50mA(工作)/10mA(待

3254968421的博客 205

Dify智能体开发:Dify文件上传

相较于聊天文本,文档文件能够承载大量的信息,例如学术报告、法律合同。受限于 LLM 自身仅能够支持文件或图片,难以获取文件内更加丰富的上下文信息,应用的使用者不得不手动复制粘贴大量信息与 LLM 对话,增加了许多不必要的使用成本。

王国平的博客 2590

C++11:右值引用

本文详细介绍了C++11中的右值引用

主要为C++知识点、Linux知识点,计算机组成结构笔记。 1445

Python 爬虫实战:深入闲鱼平台,抓取二手好物价格波动数据

本文介绍了如何利用Python爬虫抓取闲鱼(Xianyu)二手交易平台的商品价格数据并分析其波动趋势。通过requests和BeautifulSoup库实现网页数据抓取与解析,使用pandas进行数据清洗和存储,最后借助matplotlib可视化价格波动情况。文章详细展示了从网页结构分析、数据采集到波动率计算和趋势可视化的完整流程,并建议通过定时任务实现持续数据更新。该项目能为二手市场交易者提供价格参考,帮助优化买卖决策。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 3375

【C++】C++11右值引用

今天我们正式进入C++11的学习,C++11引入的一个非常重要的语法就是右值引用,在C++11之前的C++版本我们所提的引用都是左值引用,那么右值引用与左值引用又有什么区别呢?什么是左值?什么是右值?右值引用的价值体现在哪里?那么接下来我们就来学习有关右值引用的相关知识。

℉f的博客 2247

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

C++11 左值、右值、右值引用详解

左值、右值在C++11中所有的值必属于左值、右值两者之一,右值又可以细分为纯右值、将亡值。在C++11中可以取地址的、有名字的就是左值,反之,不能取地址的、没有名字的就是右值(将亡值或纯右值)。

Hyman's Blog 4万+

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

C++11特性——右值引用

首先介绍下左右值(我发现自己学了好长时间都没有对两者进行区分~)对于左值、右值可以简单的以放在等号左右为区分,等号左边的是左值,等号右边的是右值。再来详细的介绍下各自的特点:左值:1)左值可以取地址2)左值可以修改3)左值可以放在等号左右两边右值:1)右值不可以取地址2)右值不可以直接修改3)右值只能放在等号右边4)右值往往是没有名称的再来举几个实例:左值举例:int a;int a = 3;上面的a都是左值纯右值、将亡值。...

gls_nuaa的博客 7040

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

C++11——右值引用

前言 在C++98中也有一个引用,为左值引用,但是左值引用有一些不足。而C++11的右值引用的提出弥补了左值引用的不足。 左值引用和右值引用都是别名。 说明:下面说引用都代表C++98的左值引用。 一.右值引用的概念 右值引用也是一块空间的别名。只能对右值进行引用。使用是在类型后面加两个&&。 #include<iostream> using namespace std; int Add(int x,...

weixin_57023347的博客 9488

【C++】C++11语法之右值引用

关于C++11新语法的一些理解以及对其中右值引用的使用的讲解。

jhao的博客 5609

【C++11】右值引用

关于左值,右值引用的介绍

喜欢编写一些小程序的科班菜鸟,但是由于准备考研,博客不能及时更新了,不好意思! 2424

C++11右值引用

文章目录左值和右值左值,右值与引用的关系右值的特殊点左值引用的应用场景和短板移动语义关于move完美转发(&& 和 forward)总结 左值和右值 一般没有明确的定义。 左值有以下性质: 左值可以取地址 左值可以修改(除了const的左值) 左值可以放在等号左边,也可以放在等号右边 右值有以下性质: 右值不可以取地址 右值不可以修改 右值只能放在等号右边 最重要的性质是左值可以取地址,右值不可以取地址。 常量,表达式的返回值,非左值的函数返回值是右值 如下: 10 x + y;

m0_51641706的博客 1770

C++11之右值引用

本文内容包括左值及左值引用的概念理解和右值及右值引用的概念理解以及他们区分、右值引用的功能、右值引用通过移动语义实现资源转换的原理、万能引用也叫引用折叠的概念以及触发的情况、完美转发解决的问题、C++11通过右值引用对于STL标准库中的容器产生的变化等等。

2302_80475369的博客 1324

c++11为什么要引入右值引用

本文适合对c++11刚入门的小伙伴阅读。 本文加深对左值引用、右值引用、左值右值的理解。

waxtear的博客 7780

C++11 右值引用

首先,介绍一下左右值:左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋 值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左 值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。int main()// 以下的p、b、c、*p都是左值int b = 1;// 以下几个是对上面左值的左值引用return 0;

ayf9999的博客 1109

【C++ 11】&& 右值引用

【代码】【C++ 11】右值引用。

普罗米修斯的博客 1002

【C++11】学习C++就看这篇--->右值&右值引用

本篇博客详细介绍C++11中右值引用相关知识,并进行了逐步的解析,看完你对右值引用会有非常深层次的理解,你定会有非常大的收获!

熬夜秃顶中...... 1429

【c++11】 左值引用和右值引用

右值引用详解

Tom_猫的博客 874
上一篇: 一个简单的TCP自定义通信协议
下一篇: linux高级I/O函数sendfile
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值