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

2024-01-09 17:12

本文主要是介绍【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;
}

 

运行结果

这篇关于【cmu15445c++入门】(2)c++中的std::move() 左值引用右值引用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/587842

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题:

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联