【cmu15445c++入门】(2)c++中的std::move() 左值引用右值引用

左值右值

要理解move语义,必须理解左值和右值的概念。左值的简化定义是左值是对象,指向内存中某个位置。右值是左值之外的任何。

std::move() 

move语义,在C++中是一个有用的方法,它允许在对象之间高效和优化地转移数据所有权。move语义的主要目标之一是提高性能,因为移动对象比深度复制对象更快、更高效。

std::move 是将对象从一个左值移动到另一个左值的最常见方法。

std::move 将表达式转换为右值。这允许我们将左值作为右值进行交互,并允许所有权从一个左值转移到另一个左值。

代码

/**
 * @file move_semantics.cpp
 * @author Abigale Kim (abigalek)
 * @brief Tutorial code for move semantics.
 */

// Move semantics in C++ are a useful concept that allows for the efficient
// and optimized transfer of ownership of data between objects. One of the
// main goals of move semantics is to increase performance, since moving an
// object is faster and more efficient than deep copying the object.
// move语义,在C++中是一个有用的方法,它允许在对象之间高效和优化地转移数据所有权。
// move语义的主要目标之一是提高性能,因为移动对象比深度复制对象更快、更高效

// To understand move semantics, one must understand the concept of lvalues
// and rvalues. A simplified definition of lvalues is that lvalues are objects
// that refer to a location in memory. Rvalues are anything that is not a
// lvalue.
//要理解move语义,必须理解左值和右值的概念。左值的简化定义是左值是对象,指向内存中某个位置。右值是左值之外的任何。

// std::move is the most common way of moving an object from one lvalue to
// another. std::move casts an expression to a rvalue. This allows for us to
// interact with a lvalue as a rvalue, and allows for the ownership to be
// transferred from one lvalue to another.
// std::move 是将对象从一个左值移动到另一个左值的最常见方法。
// std::move 将表达式转换为右值。这允许我们将左值作为右值进行交互,并允许所有权从一个左值转移到另一个左值。

// In the code below, we include some examples for identifying whether
// expressions in C++ are lvalues or rvalues, how to use std::move, and passing
// rvalues references into functions.
//在下面的代码中,我们提供了一些示例,用于识别 C++ 中的表达式是左值还是右值,如何使用std::move以及将右值引用传递到函数中。

// Includes std::cout (printing) for demo purposes.
#include <iostream>
// Includes the utility header for std::move.
#include <utility>
// Includes the header for std::vector. We'll cover vectors more in
// containers.cpp, but what suffices to know for now is that vectors are
// essentially dynamic arrays, and the type std::vector<int> is an array of
// ints. Mainly, vectors take up a non-negligible amount of memory, and are here
// to show the performance benefits of using std::move.
#include <vector>

// Function that takes in a rvalue reference as an argument.
// It seizes ownership of the vector passed in, appends 3 to
// the back of it, and prints the values in the vector.
// 这个函数传入一个右值引用,函数夺取传入的向量的所有权,并添加"3"在向量的最后,然后输出整个vector.
void move_add_three_and_print(std::vector<int> &&vec) {
  // 专利的move会产生"夺权"
  std::vector<int> vec1 = std::move(vec);
  vec1.push_back(3);
  for (const int &item : vec1) {
    std::cout << item << " ";
  }
  std::cout << "\n";
}

// Function that takes in a rvalue reference as an argument.
// It appends 3 to the back of the vector passed in as an argument,
// and prints the values in the vector. Notably, it does not seize
// ownership of the vector. Therefore, the argument passed in would
// still be usable in the callee context.

// 这个函数传入一个右值引用,函数中添加"3"在向量的最后,并打印向量中的值。
//值得注意的是,它不会夺取向量的所有权.因此,传入的参数在被调用方上下文中仍可用。
void add_three_and_print(std::vector<int> &&vec) {
  vec.push_back(3);
  for (const int &item : vec) {
    std::cout << item << " ";
  }
  std::cout << "\n";
}

int main() {
  // Take this expression. Note that 'a' is a lvalue, since it's a variable that
  // refers to a specific space in memory (where 'a' is stored). 10 is a rvalue.
  int a = 10;//a是一个左值,因为它指向了一块特殊的内存空间。10是一个右值。

  // Let's see a basic example of moving data from one lvalue to another.
  // We define a vector of integers here.
  std::vector<int> int_array = {1, 2, 3, 4};

  // Now, we move the values of this array to another lvalue.
  std::vector<int> stealing_ints = std::move(int_array);// 一个左值move到另一个左值

  // Rvalue references are references that refer to the data itself, as opposed
  // to a lvalue. Calling std::move on a lvalue (such as stealing_ints) will
  // result in the expression being cast to a rvalue reference.
  // 右值引用是引用数据本身的引用,而不是左值。对左值(如 stealing_ints)调用std::move将导致表达式被强制转换为右值引用。
  std::vector<int> &&rvalue_stealing_ints = std::move(stealing_ints);

  // However, note that after this, it is still possible to access the data in
  // stealing_ints, since that is the lvalue that owns the data, not
  // rvalue_stealing_ints.
  //但是,请注意,在此之后,仍然可以在 stealing_ints 中访问数据,因为这是拥有数据的左值,而不是rvalue_stealing_ints。
  std::cout << "Printing from stealing_ints: " << stealing_ints[1] << std::endl;
  std::cout << "Printing from rvalue_stealing_ints: " << rvalue_stealing_ints[1] << std::endl;

  //这里下面这行直接报错退出,因为int_array对象的所有权已经没了。
  //std::cout << "Printing from int_array: " << int_array[1] << std::endl;


  // It is possible to pass in a rvalue reference into a function. However,
  // once the rvalue is moved from the lvalue in the caller context to a lvalue
  // in the callee context, it is effectively unusable to the caller.
  // Essentially, after move_add_three_and_print is called, we cannot use the
  // data in int_array2. It no longer belongs to the int_array2 lvalue.

  //可以将右值引用传递到函数中。但是,一旦右值从调用方上下文中的左值移动到被调用方上下文中的左值,
  //调用方实际上就无法使用它。从本质上讲,调用 move_add_three_and_print 后,
  //我们不能在 int_array2 中使用数据。它不再属于int_array2左值。
  std::vector<int> int_array2 = {1, 2, 3, 4};
  std::cout << "Calling move_add_three_and_print...\n";
  move_add_three_and_print(std::move(int_array2));

  // It would be unwise to try to do anything with int_array2 here. Uncomment
  // the code to try it out! (On my machine, this segfaults...) NOTE: THIS MIGHT
  // WORK FOR YOU. THIS DOES NOT MEAN THAT THIS IS WISE TO DO! 
  // std::cout << int_array2[1] << std::endl;
  //如果在这里尝试使用int_array2,例如输出其中的一个值,那么会报错退出。因为在函数里面使用了move。

  // If we don't move the lvalue in the caller context to any lvalue in the
  // callee context, then effectively the function treats the rvalue reference
  // passed in as a reference, and the lvalue in this context still owns the
  // vector data.
  //如果在调用的函数里面没有使用move,那么函数会把右值引用转换为一个引用,情切左值仍然具有对象的使用权。
  std::vector<int> int_array3 = {1, 2, 3, 4};
  std::cout << "Calling add_three_and_print...\n";
  add_three_and_print(std::move(int_array3));

  // As seen here, we can print from this array.
  std::cout << "Printing from int_array3: " << int_array3[4] << std::endl;

  // 仅仅调用一次move方法
  std::vector<int> int_array4 = {1, 2, 3, 4};
  std::move(int_array4);
  std::cout << "Printing from int_array4: " << int_array4[1] << std::endl;

  // 调用move 给一个右值
  std::vector<int> int_array5 = {1, 2, 3, 4};
  std::vector<int> &&rvalue_stealing_intsstd5 = std::move(int_array5);
  std::cout << "Printing from rvalue_stealing_intsstd5: " << rvalue_stealing_intsstd5[1] << std::endl;
  std::cout << "Printing from int_array5: " << int_array5[1] << std::endl;

  // 调用move 给一个左值
  std::vector<int> int_array6 = {1, 2, 3, 4};
  std::vector<int> rvalue_stealing_intsstd6 = std::move(int_array6);
  std::cout << "Printing from rvalue_stealing_intsstd6: " << rvalue_stealing_intsstd6[1] << std::endl;
  // 下面这一行会报错退出
  std::cout << "Printing from int_array6: " << int_array6[1] << std::endl;
  return 0;
}

 

运行结果

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机创新协会冬令营——暴力枚举题目06

我给大家第一阶段的最后一道题就到这里了&#xff0c;下次得过段时间了。所以这道题简单一点。但是足够经典 下述题目描述和示例均来自力扣&#xff1a;两数之和 题目描述 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target …

基于SpringBoot微信小程序的宠物美容预约系统设计与实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行交流合作✌ 主要内容&#xff1a;SpringBoot、Vue、SSM、HLM…

学校服务器安装anaconda并配置pytorch环境

学校服务器安装anaconda并配置pytorch环境 1.下载Anaconda2.传到xftp中3.在终端运行脚本命令4.安装pytorch4.1 查看cuda版本4.2 创建自己的环境4.3 下载pytorch4.4 验证pytorch是否安装成功 参考视频&#xff1a;远程服务器安装anaconda并配置pytorch环境 使用服务器运行项目&a…

Kafka(五)生产者

目录 Kafka生产者1 配置生产者bootstrap.serverskey.serializervalue.serializerclient.id""acksallbuffer.memory33554432(32MB)compression.typenonebatch.size16384(16KB)max.in.flight.requests.per.connection5max.request.size1048576(1MB)receive.buffer.byte…

UE5.1报错 | C2628: “SNormalDistributionWidget”后面接“void”是非法的(是否忘记了“;”?)

UE5.1报错 | C2628: “SNormalDistributionWidget”后面接“void”是非法的(是否忘记了“;”?) 报错&#xff1a; UE5.1报错 | C2628: “SNormalDistributionWidget”后面接“void”是非法的(是否忘记了“;”?) 解决&#xff1a; 检查定义类的时候&#xff0c;反花括号“…

[每周一更]-(第82期):选购NAS中重要角色RAID

网络附加存储&#xff08;NAS&#xff09;在现代数字生活中扮演着至关重要的角色&#xff0c;而对于NAS的选择中&#xff0c;关注RAID的重要性更是不可忽视的。 数据存储和安全越来越受关注&#xff1b; 为什么要使用NAS&#xff1f; 集中式存储&#xff1a; NAS提供了一个集中…

利用Python实现每日新闻早报推送

本文将介绍如何使用Python编写简单的逻辑&#xff0c;通过调用API接口实现每日新闻推送功能。 步骤&#xff1a; 导入所需的库&#xff1a; 在代码的开头&#xff0c;我们需要导入所需的库。通常&#xff0c;我们会使用requests库来发送HTTP请求&#xff0c;以获取新闻数据。 …

全栈自动化测试面试题含答案和学习路线(适合各级软件测试人员)

在面试战场上&#xff0c;我们需要像忍者一样灵活&#xff0c;像侦探一样聪明&#xff0c;还要像无敌铁金刚一样坚定。只有掌握了这些技巧&#xff0c;我们才能在面试的舞台上闪耀光芒&#xff0c;成为那个令HR们心动的测试人 前言&#xff1a; 我相信大多测试开发的或多或少经…

用户管理第2节课--idea 2023.2 后端--实现基本数据库操作(操作user表) -- 自动生成 --合并生成后的代码【鱼皮】

一、模块页面功能 1.1 domain 【实体对象】 1.2 mapper 【操作数据库的对象】--> UserMapper 1&#xff09;UserMapper 其实就是我们用来操作数据库的一个对象 2) 继承了mybatis- plus&#xff0c;它会自动帮我们去定义一些增删改查的方法。 继承可以看下图&#xf…

数据结构线性表之顺序表

一、线性表及顺序表概念 1.线性表的概念&#xff1b; 线性表是零个或多个具有相同特性的数据元素组成的有限序列&#xff0c;线性表是实际中&#xff0c;广泛使用的一种数据结构&#xff0c;相关的有&#xff1a;顺序表&#xff0c;链表&#xff0c;栈&#xff0c;队列&#…

Python私有变量的定义与访问

class Student():def __init__(self, name, age):self.name nameself.age ageself.__score 0def marking(self, score):if score < 0:return 分数不能为0self.__score scoreprint(self.name 同学本次得分是: str(self.__score)) def __talk(self): # 私有的类可通过在…

如果你创业总失败,不妨看看爷叔是如何创业的!未来三年最大创业风口,2024普通人怎么创业

自从央视点评《繁花》“剧”有强调之后&#xff0c;该电视剧的播放量就节节高升。同时&#xff0c;剧中精彩的商业的大战让人们直呼过瘾&#xff0c;其中的爷叔准确的商业眼光&#xff0c;经典的商业理论也让许多创业者得到了启示。 一、爷叔创业语录 1、做生意要讲究“派头、…

目标检测-One Stage-CenterNet

文章目录 前言一、CenterNet的网络结构和流程二、CenterNet的创新点总结 前言 前文提到的YOLOv3、YOLOv4、YOLOv5都是基于Anchor的算法&#xff08;anchor-based&#xff09;&#xff0c;这类算法有如下缺点&#xff1a; 产生大量的预测框&#xff0c;计算量大正负样本不平衡…

80/20法则-扫盲和复习篇

80/20法则-扫盲和复习篇 一、80/20法则二、对于目标三、时间管理应用四、“二八定律”基本内容总结 一、80/20法则 “80/20法则”是20世纪初意大利统计学家、经济学家维尔弗雷多帕累托提出的&#xff0c;他指出&#xff1a;在任何特定群体中&#xff0c;重要的因子通常只占少数…

js逆向第14例:猿人学第7题动态字体,随风漂移

任务7:采集这5页中胜点列的数据,找出胜点最高的召唤师,将召唤师姓名填入答案中 此题采集的是胜点列表的数据如下 通过控制台审查元素查看,可以看到是乱码,记得几年前的快手,小红书,抖音也采用了此类反爬措施,html页面显示的是乱码,浏览器能正常显示数据,大概率就是…

Spark---RDD算子(单值类型转换算子)

文章目录 1.RDD算子介绍2.转换算子2.1 Value类型2.1.1 map2.1.2 mapPartitions2.1.3 mapPartitionsWithIndex2.1.4 flatMap2.1.5 glom2.1.6 groupBy2.1.7 filter2.1.8 sample2.1.9 distinct2.1.10 coalesce2.1.11 repartition2.1.12 sortBy 1.RDD算子介绍 RDD算子是用于对RDD进…

ElasticSearch 集群搭建与状态监控cerebro

单机的elasticsearch做数据存储&#xff0c;必然面临两个问题:海量数据存储问题、单点故障问题。为了解决存储能力上上限问题就可以用到集群部署。 海量数据存储问题:将索引库从逻辑上拆分为N个分片(shard)&#xff0c;存储到多个节点单点故障问题:将分片数据在不同节点备份 (r…

校园跑腿小程序(前后端已完成)可做项目,可当毕设,支持二创

此小程序为我单独在小程序上运行的结果&#xff0c;图片信息、列表信息等没有出现是因为服务器到期了&#xff0c;资源被释放了&#xff0c;无法显示。但是后端是已经实现了的&#xff0c;有兴趣的同学可以私聊我。 效果预览

数说故事×凤凰网丨2023年度重磅事件社媒影响力盘点

回首2023年的社媒热点&#xff0c;杭州亚运会引发了全民热聊&#xff0c;熊猫丫丫回国之路接力守护&#xff0c;品牌联名的酱香拿铁让人半醒半醉&#xff0c;“美拉德”的穿搭风伴随着西伯利亚的冷空气终是吹走了“多巴胺”的明丽&#xff0c;当然世界还有另一面&#xff0c;俄…

用友GRP-U8 ufgovbank.class XXE漏洞

产品简介 用友GRP-U8R10内控管理软性软性是用友公司专注于电子政务事业&#xff0c;基于云计算技术所推出的新一代产品&#xff0c;是我国行政事业财务领域专业的财务管理软件。 漏洞描述 用友GRP-U8R10 ufgovbank.class 存在XML实体注入漏洞&#xff0c;攻击者可利用xxe漏洞…