C++中的左值(lvalue)和 右值(rvalue),移动语义(move semantics)和完美转发(perfect forwarding)

C++中的左值(lvalue)和 右值(rvalue),移动语义(move semantics)和完美转发(perfect forwarding)

flyfish

在C++中,表达式可以是左值(lvalue)或右值(rvalue)。左值和右值的区别主要在于它们的值类别(value category)和它们在表达式中的使用方式。

左值(lvalue)
左值表示一个对象或内存位置,可以被赋值或取地址。左值通常是具名变量、数组元素或函数调用返回的左值引用。

右值(rvalue)
右值表示一个临时值或字面常量,不能被赋值,但可以用于初始化另一个对象或被移动。

左值示例

在这个示例中,x 和 y 都是左值,因为它们表示内存中的一个对象,可以被赋值和取地址。

#include <iostream>int main() {int x = 10;      // 变量 x 是左值,可以被赋值int y = x;       // 变量 x 是左值,可以用于赋值int* p = &x;     // 变量 x 是左值,可以取地址std::cout << "x: " << x << std::endl;std::cout << "y: " << y << std::endl;std::cout << "Address of x: " << p << std::endl;return 0;
}
x: 10
y: 10
Address of x: 0000008C979DF694

右值示例

在这个示例中,表达式 x + 5 和字面常量 42 都是右值,因为它们表示临时值,不可以取地址。

#include <iostream>int main() {int x = 10;int y = x + 5;   // 表达式 x + 5 是右值,表示一个临时值, x + 5 不可以取地址int z = 42;      // 字面常量 42 是右值,表示一个临时值, 42不可以取地址std::cout << "x: " << x << std::endl;std::cout << "y: " << y << std::endl;std::cout << "z: " << z << std::endl;return 0;
}

左值引用和右值引用

printLvalue 函数接受左值引用参数,只能传递左值。
printRvalue 函数接受右值引用参数,只能传递右值。
调用 printRvalue(20) 和 printRvalue(a + 5) 都是传递右值,而调用 printLvalue(a) 是传递左值。

#include <iostream>// 左值引用参数
void printLvalue(int& x) {std::cout << "Lvalue: " << x << std::endl;
}// 右值引用参数
void printRvalue(int&& x) {std::cout << "Rvalue: " << x << std::endl;
}int main() {int a = 10;printLvalue(a);       // 传递左值printRvalue(20);      // 传递右值printRvalue(a + 5);   // 传递右值printRvalue(std::move(a)); // 将左值转换为右值return 0;
}

输出

Lvalue: 10
Rvalue: 20
Rvalue: 15
Rvalue: 10

std::move

std::move 是 C++11 引入的一个标准库函数,用于将对象显式地转换为右值引用(rvalue reference)。它的主要作用是启用对象的移动语义,从而避免昂贵的拷贝操作,提升程序的性能。

std::move 的工作原理
std::move 本质上不会移动任何东西,它只是将其参数转换为右值引用,使其可以被移动构造函数或移动赋值运算符处理。这样可以避免深拷贝,提高效率。

下面的例子std::move 将 vec1 转换为右值引用,允许 vec2 通过移动构造函数获取 vec1 的内容。移动之后,vec1 的大小变为 0,因为其资源已被转移给 vec2。

#include <iostream>
#include <utility>  // std::move
#include <vector>int main() {std::vector<int> vec1 = {1, 2, 3, 4, 5};std::vector<int> vec2;// 使用 std::move 将 vec1 转换为右值引用,vec2 移动构造 vec1 的内容vec2 = std::move(vec1);std::cout << "vec1 size: " << vec1.size() << std::endl;  // 输出:vec1 size: 0std::cout << "vec2 size: " << vec2.size() << std::endl;  // 输出:vec2 size: 5return 0;
}

输出

vec1 size: 0
vec2 size: 5

移动语义(Move Semantics)

移动语义是C++11引入的特性,用于优化对象的复制操作,避免不必要的深拷贝,提高程序的性能。它通过使用右值引用(&&)实现对象的移动,而不是复制。

下面是一个带有移动构造函数和移动赋值运算符的自定义类示例
MyClass 有一个带动态内存分配的构造函数。
移动构造函数将资源从源对象转移到目标对象,并将源对象的指针置空。
移动赋值运算符类似,将资源从源对象转移到目标对象,并释放目标对象的原有资源。

#include <iostream>
#include <vector>class MyClass {
public:MyClass(int size) : size(size), data(new int[size]) {std::cout << "Constructor called\n";}// 移动构造函数MyClass(MyClass&& other) noexcept : size(other.size), data(other.data) {other.size = 0;other.data = nullptr;std::cout << "Move constructor called\n";}// 移动赋值运算符MyClass& operator=(MyClass&& other) noexcept {if (this != &other) {delete[] data;size = other.size;data = other.data;other.size = 0;other.data = nullptr;std::cout << "Move assignment operator called\n";}return *this;}~MyClass() {delete[] data;std::cout << "Destructor called\n";}private:int size;int* data;
};int main() {MyClass obj1(10);MyClass obj2 = std::move(obj1);  // 调用移动构造函数MyClass obj3(20);obj3 = std::move(obj2);          // 调用移动赋值运算符return 0;
}

输出

Constructor called
Move constructor called
Constructor called
Move assignment operator called
Destructor called
Destructor called
Destructor called

完美转发(Perfect Forwarding)

完美转发允许函数模板将其参数完美地传递给另一个函数,而不改变参数的值类别(左值或右值)。这通常通过使用 std::forward 实现。

完美转发示例
wrapper 函数模板使用 std::forward 将参数完美转发给 process 函数。
process 函数有两个重载版本,一个接受左值引用,另一个接受右值引用。
wrapper 函数根据传入参数的值类别,正确调用对应的 process 函数。

#include <iostream>
#include <utility>  // std::forward// 泛型函数,用于完美转发参数
template<typename T>
void wrapper(T&& arg) {process(std::forward<T>(arg));
}// 被调用的函数
void process(int& x) {std::cout << "Processing lvalue: " << x << std::endl;
}void process(int&& x) {std::cout << "Processing rvalue: " << x << std::endl;
}int main() {int a = 5;wrapper(a);          // 传递左值,调用 void process(int& x)wrapper(10);         // 传递右值,调用 void process(int&& x)wrapper(std::move(a)); // 传递移动的左值,调用 void process(int&& x)return 0;
}

输出

Processing lvalue: 5
Processing rvalue: 10
Processing rvalue: 5

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

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

相关文章

HarmonyOS应用开发者高级认证,Next版本发布后最新题库 - 多选题序号3

基础认证题库请移步&#xff1a;HarmonyOS应用开发者基础认证题库 注&#xff1a;有读者反馈&#xff0c;题库的代码块比较多&#xff0c;打开文章时会卡死。所以笔者将题库拆分&#xff0c;单选题20个为一组&#xff0c;多选题10个为一组&#xff0c;题库目录如下&#xff0c;…

全面解析:构建基于深度学习的安全帽检测系统(UI界面+YOLO代码+数据集)

注意看全文的结尾作者的声明 一、引言 1. 项目背景与动机 在建筑工地等高危场所&#xff0c;佩戴安全帽是保护工人安全的基本措施。然而&#xff0c;工人有时会忘记佩戴安全帽或者佩戴不规范。为了提高现场安全管理效率&#xff0c;我们引入了基于深度学习的安全帽检测系统&…

Linux 驱动学习笔记

1、驱动程序分为几类&#xff1f; • 内核驱动程序&#xff08;Kernel Drivers&#xff09;&#xff1a;这些是运行在操作系统内核空间的驱动程序&#xff0c;用于直接访问和控制硬件设备。它们提供了与硬件交互的底层功能&#xff0c;如处理中断、访问寄存器、数据传输等。 •…

List类型实体属性XML和JSON情景下的序列号和反序列化

反序列化 JsonProperty(“SaleOrders”)可以识别xml和json JsonProperty(“SaleOrders”) private List saleOrders; Data JacksonXmlRootElement(localName "SaleOrder") JsonIgnoreProperties(ignoreUnknown true) public class SaleOrder {}序列化 变成json可…

TCP并发服务器多线程

1.创建线程‐‐pthread_create int pthread_create( pthread_t *thread, // 线程 ID 无符号长整型 const pthread_attr_t *attr, // 线程属性&#xff0c; NULL void *(*start_routine)(void *), // 线程处理函数 void *arg); // 线程处理函数 参数&#xff1a; pthrea…

安装Ubuntu24.04服务器版本

Ubuntu系统安装 一.启动安装程序二.执行 Ubuntu Server 安装向导1.选择安装程序语言&#xff0c;通常选择「English」2.设置键盘布局&#xff0c;默认「English US」即可3.选择安装方式 三.配置网络1.按Tab键选择网络接口&#xff08;例如 ens160&#xff09;&#xff0c;然后按…

2024视频改字祝福 豪车装X系统源码uniapp前端源码

源码介绍 uniapp视频改字祝福 豪车装X系统源码 全开源,只有uniapp前端&#xff0c;API接口需要寻找对应的。 创意无限&#xff01;AI视频改字祝福&#xff0c;豪车装X系统源码开源&#xff0c;打造个性化祝福视频不再难&#xff01; 想要为你的朋友或家人送上一份特别的祝福…

如何解决ChromeDriver 126找不到chromedriver.exe问题

引言 在使用Selenium和ChromeDriver进行网页自动化时&#xff0c;ChromeDriver与Chrome浏览器版本不匹配的问题时有发生。最近&#xff0c;许多开发者在使用ChromeDriver 126时遇到了无法找到chromedriver.exe文件的错误。本文将介绍该问题的原因&#xff0c;并提供详细的解决…

简化AI模型:PyTorch量化技术在边缘计算中的应用

引言 在资源受限的设备上部署深度学习模型时&#xff0c;模型量化技术可以显著提高模型的部署效率。通过将模型的权重和激活从32位浮点数转换为更低位数的值&#xff0c;量化可以减少模型的大小&#xff0c;加快推理速度&#xff0c;同时降低能耗。 模型量化概述 定义与优势…

SpringBoot中如何使用RabbitMq

一&#xff0c;RabbitMQ简介和基本概念 RabbitMQ 是一个开源的消息中间件&#xff0c;基于 AMQP&#xff08;高级消息队列协议&#xff09;实现。 它由 Erlang 语言开发&#xff0c;并且支持多种编程语言&#xff0c;包括 Java、Python、Ruby、PHP 和 C# 等&#xff0c; 下载…

JCR一区级 | Matlab实现CPO-Transformer-LSTM多变量回归预测【2024新算法】

JCR一区级 | Matlab实现CPO-Transformer-LSTM多变量回归预测【2024新算法】 目录 JCR一区级 | Matlab实现CPO-Transformer-LSTM多变量回归预测【2024新算法】效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.【JCR一区级】Matlab实现CPO-Transformer-LSTM多变量回归预测…

<数据集>AffectNet表情识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;29752张 标注数量(xml文件个数)&#xff1a;29752 标注数量(txt文件个数)&#xff1a;29752 标注类别数&#xff1a;7 标注类别名称&#xff1a;[anger,contempt,disgust,fear,happy,neutral,sad,surprise] 序号类…

新手小白的pytorch学习第十弹----多类别分类问题模型以及九、十弹的练习

目录 1 多类别分类模型1.1 创建数据1.2 创建模型1.3 模型传出的数据1.4 损失函数和优化器1.5 训练和测试1.6 衡量模型性能的指标 2 练习Exercise 之前我们已经学习了 二分类问题&#xff0c;二分类就像抛硬币正面和反面&#xff0c;只有两种情况。 这里我们要探讨一个 多类别…

css之margin塌陷

margin塌陷 一、margin塌陷的概念二、代码演示三、效果图示描述四、解决后的效果 一、margin塌陷的概念 margin塌陷是指在CSS布局中&#xff0c;当两个或多个元素的垂直margin&#xff08;上外边距和下外边距&#xff09;相遇时&#xff0c;它们不会按照预期叠加&#xff0c;而…

leetcode-78. 子集

题目描述 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的 子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[],[1],…

高职国培丨数据分析与数据挖掘课程实施能力提升培训班正式开班

7月15日&#xff0c;由广东机电职业技术学院牵头&#xff0c;广东泰迪智能科技股份有限公司作为合作单位的“高职教师数据分析与数据挖掘课程实施能力提升培训班&#xff08;高职国培&#xff09;”正式开班。来自广东省各地36位高校教师参与本次线下师资国培班。 广东机电职业…

11 - FFmpeg - 编码 AAC

Planar 模式是 ffmpeg内部存储模式&#xff0c;我们实际使用的音频文件都是Packed模式的。 FFmpeq解码不同格式的音频输出的音频采样格式不是一样。 其中AAC解码输出的数据为浮点型的 AV_SAMPLE_FMT_FLTP 格式&#xff0c;MP3 解码输出的数据为 AV_SAMPLE_FMT_S16P 格式(使用的…

【区块链 + 智慧政务】南京发改委:基于区块链的项目评审与专家管理系统 | FISCO BCOS应用案例

围绕招投标、项目评审过程中的信息化管理&#xff0c;南京市发展和改革委员会上线基于区块链的项目评审与专家管理系统&#xff0c; 规范南京市发改委专家评审&#xff08;咨询&#xff09;活动&#xff0c;健全专家库管理机制&#xff0c;提升行政决策质量和政策研究水平。该系…

HarmonyOS 状态管理(一)

1. HarmonyOS 状态管理 1.1. 说明 官方文档&#xff08;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-state-management-V5&#xff09; 1.1.1. 状态管理&#xff08;V1稳定版&#xff09; 状态管理&#xff08;V1稳定版&#xff09;提供了多种…

【iOS】——SideTable

SideTable Side Table主要用于存储和管理对象的额外信息&#xff0c;特别是与弱引用相关的数据。Side Table的设计和使用是Objective-C运行时实现弱引用的基础&#xff0c;使得ARC&#xff08;Automatic Reference Counting&#xff09;能够正确地处理弱引用的生命周期。 新版…