【C++11】左值引用、右值引用、移动语义和完美转发

🦄个人主页:修修修也

🎏所属专栏:C++

⚙️操作环境:Visual Studio 2022


目录

📌左值引用和右值引用

🎏左值和左值引用

🎏右值和右值引用

📌左值引用和右值引用比较 

🎏左值引用

🎏右值引用

📌左值引用和右值引用使用场景和意义

🎏左值引用使用场景和意义

🎏右值引用使用场景和意义

 🎏右值引用引用左值及其使用场景

📌完美转发

🎏为什么需要完美转发?

🎏如何实现完美转发?

 🎏完整示例

结语


📌左值引用和右值引用

        我们在一开始学习c++时就学习过引用的语法,当时我们将引用这一语法理解为给变量起别名。在c++11当中新增了右值引用语法特性,无论是左值引用还是右值引用,都是给对象起别名。注意,要摒弃一个误区,不能简单的认为在赋值号左边的就叫左值,右边的就叫右值,实际上左值右值的界定需要参照以下定义:


🎏左值和左值引用

        左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址,一般可以对它赋值,左值可以出现在赋值符号的左边,右值不能出现在赋值符号的左边.定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址,因此还是左值.

        左值引用就是给左值的引用,给左值取别名.如:

//左值引用
int a = 0;
int& r1 = a; //给a取别名为r1

🎏右值和右值引用

       右值是一个表示数据的表达式,如:字面常量, 表达式返回值, 函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现在赋值符号的左边,右值不能取地址.

        右值引用就是对右值的引用,给右值取别名.如:

//右值引用
int&& r5 = 10; //给10取别名为r5double x = 1.1, y = 2.2;
double&& r6 = x + y; //给表达式x+y取别名为r6

📌左值引用和右值引用比较 

🎏左值引用

  1. 左值引用只能引用左值,不能引用右值
  2. 但是const左值引用既可以引用左值,也可以引用右值
/左值引用引用右值
double x = 2.2;
double y = 3.3;
const int& r2 = 10;
const double& r3 = x + y;//这里x和y都是左值,但是x+y表达式返回的结果5是一个临时变量是右值

🎏右值引用

  1. 右值引用只能引用右值,不能引用左值.
  2. 但是特殊情况下右值引用可以引用move以后的左值.
//右值引用引用左值
int a = 10;
int&& r7 = move(a);

        也就是说,正常情况下左值只能引用左值, 右值只能引用右值, 但是const左值可以引用右值,右值可以引用move后的左值。


📌左值引用和右值引用使用场景和意义

🎏左值引用使用场景和意义

左值引用使用场景:

  1. 做参数
    void swap(int& a,int&b) //左值引用可以直接修改原对象,减少参数传递时的拷贝
    {int tmp = a;a = b;b = tmp;
    }int main()
    {int x = 2;int y = 3;swap(x,y);return 0;
    }
    
  2. 做返回值
    //左值引用可以直接修改返回值,同时减少了函数传值返回的拷贝
    int& get(size_t pos)
    {return data[pos];
    }

左值引用意义: 减少拷贝,并可以直接修改原对象

左值引用的缺点:但是当函数返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回,只能传值返回。例如:

        函数中可以看到,这里只能使用传值返回,传值返回会导致至少1次拷贝构造(如果是一些旧一点的编译器可能是两次拷贝构造)。


🎏右值引用使用场景和意义

        通过上面我们对左值引用使用场景和意义的分析,我们得知了左值引用的短板。因此C++的大佬们就引入了右值引用和移动语义来解决这个问题:移动语义包括移动构造和移动赋值,我们先来看移动构造:

        移动构造本质是将参数右值的资源窃取过来,占为已有,那么就不用做深拷贝了,所以它叫做移动构造,就是窃取别人的资源来构造自己:

        而移动赋值也是将赋值运算符右边的右值资源窃取过来,占为己有,也就不用再做深拷贝了:

        基于上面的概念,实现的string类移动构造和移动赋值函数如下:

//移动构造
string(string&& s):_str(nullptr), _size(0), _capacity(0)
{swap(s);
}//移动赋值
string& operator=(string&& s)
{swap(s);return *this;
}

 🎏右值引用引用左值及其使用场景

        有些场景下,我们可能需要用右值去引用左值实现移动语义。当需要用右值引用引用一个左值时,可以通过move函数将左值转化为右值。

int main()
{string s1("hello world");// 这里s1是左值,调用的是拷贝构造string s2(s1);// 这里我们把s1 move处理以后, 会被当成右值,调用移动构造// 但是这里要注意,一般是不要这样用的,因为我们会发现s1的// 资源被转移给了s3,s1被置空了。string s3(std::move(s1));return 0;
}


📌完美转发

        完美转发(Perfect Forwarding) 是 C++11 引入的核心特性之一,用于在泛型编程中精确传递参数的左值/右值属性,避免不必要的拷贝或类型损失。它结合了 右值引用万能引用(Universal Reference) 和 std::forward 实现。


🎏为什么需要完美转发?

        假设有一个泛型函数 wrapper,需要将参数转发给另一个函数 target

template<typename T>
void wrapper(T arg){target(arg);  // 直接传递参数
}

问题:

  1. 值类别丢失:无论 arg 是左值还是右值,target(arg) 接收的始终是左值(因为右值引用本身是左值, 如果右值引用本身是右值那么就没法移动语义了)所以左值引用和右值引用传递到下层都变成了左值引用。

  2. 拷贝开销:若 arg 是临时对象(右值),无法触发移动语义,可能导致深拷贝。

         右值引用默认是左值,我们才能基于此实现移动语义:

        但是如果不支持完美转发的话,右值引用无法保持右值属性,那么我们遇到嵌套容器深拷贝的情况就没法用移动语义:


🎏如何实现完美转发?

1. 万能引用(Universal Reference)

  • 语法:模板参数中使用 T&&,且 T 需要被推导(如函数模板或 auto)。

  • 特性:可以绑定到左值或右值,保留参数的原始类型信息。

  • 如果实参是左值,他就是左值引用(引用折叠)

  • 如果实参是右值,他就是右值引用

template<typename T>
void wrapper(T&& arg) {  // arg 是万能引用// 模板中的&&不代表右值引用,而是万能引用,其既能接收左值又能接收右值。// 模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力,// 但是引用类型的唯一作用就是限制了接收的类型,后续使用中都退化成了左值,// 我们希望能够在传递过程中保持它的左值或者右值的属性, 就需要用我们下面学习的完美转发
}

2. std::forward<T>

  • 作用:根据 T 的原始类型(左值或右值),将参数有条件地转换回原始类型

  • 本质:若 T 是左值引用,返回左值;否则返回右值引用(触发移动语义)。

 🎏完整示例

#include <iostream>
#include <utility>  // std::forward// 目标函数
void target(int& x)  { std::cout << "左值: " << x << std::endl; }
void target(int&& x) { std::cout << "右值: " << x << std::endl; }// 完美转发的包装函数
template<typename T>
void wrapper(T&& arg) 
{target(std::forward<T>(arg));  // 关键:保留参数的原始类型
}int main() 
{int a = 10;wrapper(a);       // 传递左值 → 调用 target(int&)wrapper(20);      // 传递右值 → 调用 target(int&&)wrapper(std::move(a)); // 显式转为右值 → 调用 target(int&&)return 0;
}

结语

希望这篇关于 C++11之左值引用,右值引用和移动语义 的博客能对大家有所帮助,欢迎大佬们留言或私信与我交流.

学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!

 相关文章推荐

【C++】STL标准模板库容器set

【C++】模拟实现二叉搜索(排序)树

【数据结构】C语言实现链式二叉树(附完整运行代码)

【数据结构】什么是二叉搜索(排序)树?

【C++】模拟实现priority_queue(优先级队列)

【C++】模拟实现queue

【C++】模拟实现stack

【C++】模拟实现list

【C++】模拟实现vector

【C++】标准库类型vector

【C++】模拟实现string类

【C++】标准库类型string

【C++】构建第一个C++类:Date类

【C++】类的六大默认成员函数及其特性(万字详解)

【C++】什么是类与对象?


强烈呼吁大家在写CSDN的时候把Ctrl+z给禁用掉,否则有一定几率导致您的创作窗口一秒穿越到n小时前。且根本没有一点办法恢复。这篇文章就是血的教训...🥲

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

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

相关文章

麒麟系列Linux发行版探秘

以下内容摘自《银河麒麟操作系统进阶应用》一书。 银河麒麟操作系统&#xff08;Kylin&#xff09; 银河麒麟&#xff08;Kylin&#xff09;操作系统是中国自主研发的一款基于Linux内核的操作系统。它的发展历程可以追溯到2002年&#xff0c;最初由国防科技大学主导研发&…

【机密计算顶会解读】11:ACAI——使用 Arm 机密计算架构保护加速器执行

导读&#xff1a;本文介绍ACAI&#xff0c;其构建一个基于CCA的解决方案&#xff0c;使得机密虚拟机能够安全地使用加速器&#xff0c;同时保持与现有应用程序的兼容性和安全性&#xff0c;能够实现对加速器的安全访问。 原文链接&#xff1a;ACAI: Protecting Accelerator Ex…

第一天 UnityShader的结构

Shader初学者的学习笔记 第一天 Unity Shader的结构 文章目录 Shader初学者的学习笔记前言一、Unity Shader结构二、Unity Shader结构解析① Properties② Tags③ RenderSetup(可选状态)④ Name⑤ [Tags]⑥ [RenderSetup]⑦ 顶点着色器和片元着色器的代码 (Unity最聪明的孩子)…

VL开源模型实现文本生成图片

一、 基础知识 根据描述生成图片的视觉-语言模型&#xff08;Vision-Language Models, VL 模型&#xff09;是近年来多模态生成领域的热点研究方向。这些模型能够根据自然语言描述生成高质量的图像&#xff0c;广泛应用于艺术创作、设计辅助、虚拟场景构建等领域。 1 根据描述…

【Java SE】抽象类/方法、模板设计模式

目录 1.抽象类/方法 1.1 基本介绍 1.2 语法格式 1.3 使用细节 2. 模板设计模式&#xff08;抽象类使用场景&#xff09; 2.1 基本介绍 2.2 具体例子 1.抽象类/方法 1.1 基本介绍 ① 当父类的某些方法&#xff0c;需要声明&#xff0c;但是又不确定如何实现时&#xff…

【人工智能】LM Studio 的 GPU 加速:释放大模型推理潜能的极致优化

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 随着大语言模型(LLM)的广泛应用,其推理效率成为限制性能的关键瓶颈。LM Studio 作为一个轻量级机器学习框架,通过 GPU 加速显著提升了大…

深度学习:从零开始的DeepSeek-R1-Distill有监督微调训练实战(SFT)

原文链接&#xff1a;从零开始的DeepSeek微调训练实战&#xff08;SFT&#xff09; 微调参考示例&#xff1a;由unsloth官方提供https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Qwen2.5_(7B)-Alpaca.ipynbhttps://colab.research.google.com/git…

流畅如丝:利用requestAnimationFrame优化你的Web动画体验

requestAnimationFrame 是前端开发中用于优化动画性能的 API。它允许浏览器在下一次重绘之前执行指定的回调函数&#xff0c;通常用于实现平滑的动画效果。 1.作用 优化性能&#xff1a;requestAnimationFrame 会根据浏览器的刷新率&#xff08;通常是 60Hz&#xff0c;即每秒…

【pytest框架源码分析五】pytest插件的注册流程

前文介绍到pytest整体是运用插件来实现其运行流程的。这里仔细介绍下具体过程。 首先进入main方法 def main(args: list[str] | os.PathLike[str] | None None,plugins: Sequence[str | _PluggyPlugin] | None None, ) -> int | ExitCode:"""Perform an i…

IoTDB日志提示Too many open files

问题 时序数据库 IoTDB 1.3.3 版本 IoTDB 执行查询操作失败&#xff0c;日志打印提示 Too many open files。通过命令查看打开文件数&#xff0c;结果如下&#xff1a; [root0002 DataReceiver]# lsof|grep 28347|wc -l DataNode 55444 [root0002 DataReceiver]# lsof|g…

prometheus 添加alertmanager添加dingtalk机器人告警

1、dingtalk创建机器人,目前我们采用加白名单的方式校验 2、定位到如下图 test结果如下

C 语 言 --- 操 作 符 2

C 语 言 --- 操 作 符 2 移 位 操 作 符定 义原 码 补 码 和 反 码左 移&#xff08;<<&#xff09;右 移&#xff08;>>&#xff09;算 术 右 移逻 辑 右 移 按 位 与、按 位 或、和 按 位 异 或按 位 与按 位 或按 位 异 或 逻 辑 反 操 作负 值 操 作按 位 取 反…

基于Spring Boot的公司资产网站的设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

零碳工厂能源管理系统的核心技术与应用实践

零碳工厂能源管理系统是一种高效的解决方案&#xff0c;旨在优化能源使用并减少碳排放&#xff0c;以帮助工厂实现低碳或零碳的生产目标。以下是该系统的详细构成和功能&#xff1a; 1. 核心组件 传感器和监测设备&#xff1a;用于实时监测工厂内的能源使用情况&#xff0c;包…

美摄接入DeepSeek等大模型,用多模态融合重构视频创作新边界!

今年以来&#xff0c;DeepSeek凭借其强大的深度推理分析能力&#xff0c;在AI领域掀起新的热潮。美摄科技快速响应市场需求&#xff0c;迅速接入以DeepSeek、通义千问、商汤、文心一言为代表的大模型&#xff0c;为企业视频创作生产带来全新体验。 传统视频创作面临着同质化、…

JAVA————十五万字汇总

JAVA语言概述 JAVA语句结构 JAVA面向对象程序设计&#xff08;一&#xff09; JAVA面向对象程序设计&#xff08;二&#xff09; JAVA面向对象程序设计&#xff08;三&#xff09;工具类的实现 JAVA面向对象程序设计&#xff08;四&#xff09;录入异常处理 JAVA图形用户界面设…

力扣热题100(方便自己复习,自用)

力扣热题100 1. 两数之和 - 力扣&#xff08;LeetCode&#xff09; 查找两数之和是不是等于target也就是我们找到一个数之后&#xff0c;用target将其减掉&#xff0c;再寻找应当对应的元素是什么每找到一个数&#xff0c;我们就将其放在集合中&#xff0c;因为集合中可以去重…

【yolo】yolo训练报错,以及解决方案

背景&#xff1a; 刚刚&#xff0c;写了《【yolo】yolo推理报错&#xff0c;以及解决方案》&#xff0c;马上训练就遇到类似的报错。 我对我标注的图像进行了300轮的训练&#xff0c;但是训练完300轮后&#xff0c;报错了。。。 报错信息 300 epochs completed in 0.085 hou…

vscode/cursor中python运行路径设置 模块导入问题

vscode/cursor中python运行路径设置 ## 文件路径设置 问题描述 pycharm的项目用cursor运行&#xff0c;出现目录找不到 后来利用 os.getcwd()&#xff0c;经过打印调试发现是IDE的本身配置问题 pycharm中&#xff0c;os.getcwd()默认打开当前脚本所在目录 vscode/cursor中…

理解线性动力学中的模态叠加法

线性动力学中的模态叠加方法 模态叠加法是线性动力学中一种有价值的工具&#xff0c;可以有效地确定频域或时域中的系统响应。对于某些类型的线性动力学分析&#xff0c;有必要使用此方法&#xff0c;因此了解该过程对于获得准确的结果至关重要。在本博客中&#xff0c;我们将…