C++:moveforward

1.move

在C++11添加了右值引用,并且不能使用左值初始化右值引用如果想要使用左值初始化一个右值引用需要借助std::move()函数使用std::move方法可以将左值转换为右值。使用这个函数并不能移动任何东西,而是和移动构造函数一样都具有移动语义,将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存拷贝

从实现上讲,std::move基本等同于一个类型转换:static_cast<T&&>(lvalue);,函数原型如下:

template<class _Ty>
_NODISCARD constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) _NOEXCEPT
{	// forward _Arg as movablereturn (static_cast<remove_reference_t<_Ty>&&>(_Arg));
}

使用方法如下:

class Test
{
public:Test(){}......
}
int main()
{Test t;Test && v1 = t;          // errorTest && v2 = move(t);    // okreturn 0;
}
  • 在第4行中,使用左值初始化右值引用,因此语法是错误的。
  • 在第5行中,使用move()函数将左值转换为了右值,这样就可以初始化右值引用了。

假设一个临时容器很大,并且需要将这个容器赋值给另一个容器,就可以执行如下操作:

list<string> ls;
ls.push_back("hello");
ls.push_back("world");
......
list<string> ls1 = ls;        // 需要拷贝, 效率低
list<string> ls2 = move(ls);

如果不使用std::move,拷贝的代价很大,性能较低。使用move几乎没有任何代价,只是转换了资源的所有权。如果一个对象内部有较大的堆内存或者动态数组时,使用move()就可以非常方便的进行数据所有权的转移。另外,我们也可以给类编写相应的移动构造函数(T::T(T&& another))和和具有移动语义的赋值函数(T&& T::operator=(T&& rhs)),在构造对象和赋值的时候尽可能的进行资源的重复利用,因为它们都是接收一个右值引用参数。

2.forward

右值引用类型是独立于值的,一个右值引用作为函数参数的形参时,在函数内部转发该参数给内部其他函数时,它就变成一个左值,并不是原来的类型了。如果需要按照参数原来的类型转发到另一个函数,可以使用C++11提供的std::forward()函数,该函数实现的功能称之为完美转发。

// 函数原型
template <class T> T&& forward (typename remove_reference<T>::type& t) noexcept;
template <class T> T&& forward (typename remove_reference<T>::type&& t) noexcept;// 精简之后的样子
std::forward<T>(t);
  • 当T为左值引用类型时,t将被转换为T类型的左值
  • 当T不是左值引用类型时,t将被转换为T类型的右值

下面通过一个例子演示一下关于forward的使用:

#include <iostream>using namespace std;template<typename T>
void printValue(T &t) {cout << "l-value: " << t << endl;
}template<typename T>
void printValue(T &&t) {cout << "r-value: " << t << endl;
}template<typename T>
void testForward(T &&v) {printValue(v);printValue(move(v));printValue(forward<T>(v));cout << endl;
}int main() {testForward(520);//520是右值,推导出未定义引用类型是右值引用T,右值引用传递给printValue会变成左值引用//move把左值引用转换为右值//forward<T>(v)中,T是右值引用,v会被forward转换为右值引用//所以输出为l-value: 520 r-value: 520 r-value: 520int num = 1314;testForward(num);//num为左值,推导出未定义引用类型为左值引用T,传递给printValue还是为左值引用//move将左值引用转换成了右值//forward<T>(v)中,T是左值引用,v会被forward转换为左值引用//所以输出为l-value: 520 r-value: 520 l-value: 520testForward(forward<int>(num));//forward<T>(t)//当T不是左值引用类型时,t将被转换为T类型的右值//实现的步骤和testForward(520);的过程一样testForward(forward<int &>(num));//forward<T>(t)//当T为左值引用类型时,t将被转换为T类型的左值//实现的步骤和testForward(num);的过程一样testForward(forward<int &&>(num));//forward<T>(t)//当T不是左值引用类型时,t将被转换为T类型的右值//实现的步骤和testForward(520);的过程一样return 0;
}

结果如下:

l-value: 520
r-value: 520
r-value: 520l-value: 1314
r-value: 1314
l-value: 1314l-value: 1314
r-value: 1314
r-value: 1314l-value: 1314
r-value: 1314
l-value: 1314l-value: 1314
r-value: 1314
r-value: 1314
  • testForward(520);函数的形参为未定引用类型T&&实参为右值,初始化后被推导为一个右值引用
  • printValue(v);已命名的右值v,编译器会视为左值处理,实参为左值
  • printValue(move(v));已命名的右值编译器会视为左值处理,通过move又将其转换为右值,实参为右值
  • printValue(forward<T>(v));forward的模板参数为右值引用,最终得到一个右值,实参为右值
  • testForward(num);函数的形参为未定引用类型T&&,实参为左值,初始化后被推导为一个左值引用
  • printValue(v);实参为左值
  • printValue(move(v));通过move将左值转换为右值,实参为右值
  • printValue(forward<T>(v));forward的模板参数为左值引用,最终得到一个左值引用,实参为左值
  • testForward(forward<int>(num));forward的模板类型为int,最终会得到一个右值,函数的形参为未定引用类型T&&被右值初始化后得到一个右值引用类型
  • printValue(v);已命名的右值v,编译器会视为左值处理,实参为左值
  • printValue(move(v));已命名的右值编译器会视为左值处理,通过move又将其转换为右值,实参为右值
  • printValue(forward<T>(v));forward的模板参数为右值引用,最终得到一个右值,实参为右值
  • testForward(forward<int&>(num));forward的模板类型为int&,最终会得到一个左值,函数的形参为未定引用类型T&&被左值初始化后得到一个左值引用类型
  • printValue(v);实参为左值
  • printValue(move(v));通过move将左值转换为右值,实参为右值
  • printValue(forward<T>(v));forward的模板参数为左值引用,最终得到一个左值,实参为左值
  • testForward(forward<int&&>(num));forward的模板类型为int&&,最终会得到一个右值,函数的形参为未定引用类型T&&被右值初始化后得到一个右值引用类型
  • printValue(v);已命名的右值v,编译器会视为左值处理,实参为左值
  • printValue(move(v));已命名的右值编译器会视为左值处理,通过move又将其转换为右值,实参为右值
  • printValue(forward<T>(v));forward的模板参数为右值引用,最终得到一个右值,实参为右值

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

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

相关文章

matches()` 方法

matches() 方法是 Matcher 类中的一个方法&#xff0c;用于尝试将整个输入序列与模式进行匹配。如果整个输入序列与模式完全匹配&#xff0c;则返回 true&#xff1b;否则返回 false。 下面是一个示例代码&#xff1a; java Pattern pattern Pattern.compile("\\d")…

IO——标准IO

1.1概念 标准IO&#xff1a;是在C库中定义的一组专门用于输入输出的函数。 1.2特点 &#xff08;1&#xff09;通过缓冲机制减少系统调用&#xff0c;提高效率 &#xff08;2&#xff09;围绕流操作&#xff0c;用FILE*描述 &#xff08;3&#xff09;标准IO默认打开三个流&a…

PCIe错误定义与分类

前言&#xff1a; PCI总线中定义两个边带信号&#xff08;PERR#和SERR#&#xff09;来处理总线错误。其中PERR#主要对应的是普通数据奇偶校检错误&#xff08;Parity Error&#xff09;&#xff0c;而SERR#主要对应的是系统错误&#xff08;System Error&#xff09;。具体如下…

vue定义公共方法

在vue文件中挂载公共方法&#xff0c;方便在页面中直接调用&#xff0c;使页面干净整洁&#xff0c;可读性高 1、创建公共方法的js文件&#xff0c;放入常用的函数 let commonFun {a: (c) > {return c} }export default commonFun2、在main.js文件中挂载 import commonF…

数据结构复习指导之绪论(算法的概念以及效率的度量)

文章目录 绪论&#xff1a; 2.算法和算法评价 知识总览 2.1算法的基本概念 知识点回顾与重要考点 2.2算法效率的度量 知识总览 1.时间复杂度 2.空间复杂度 知识点回顾与重要考点 归纳总结 绪论&#xff1a; 2.算法和算法评价 知识总览 2.1算法的基本概念 算法( Al…

【现代C++】模块的使用

C20引入了模块的概念&#xff0c;这是一个重要的新特性&#xff0c;旨在替代传统的预处理器和头文件机制。模块旨在提高编译速度、改善代码封装性、减少名称污染&#xff0c;并提供更好的工具支持。下面详细介绍模块的关键概念和使用方法&#xff1a; 1. 模块的基本概念 模块…

openGauss学习笔记-263 openGauss性能调优-TPCC性能调优测试指导-前置软件安装

文章目录 openGauss学习笔记-263 openGauss性能调优-TPCC性能调优测试指导-前置软件安装263.1 安装jdk263.2 安装numactl263.3 安装ant263.4 安装htop工具 openGauss学习笔记-263 openGauss性能调优-TPCC性能调优测试指导-前置软件安装 本章节主要介绍openGauss数据库内核基于…

谷歌浏览器的开发者插件vue-devtools

在这里我留下一个git地址用来下载插件包&#xff0c;首先在自己喜欢的位置创建一个新的文件夹&#xff0c;起一个自己喜欢的文件夹名字&#xff0c;下载到包后&#xff0c;然后点进文件夹里下载依赖&#xff0c;npm install,下载后如下面这个样子 git clone https://gitee.com…

Android R 展讯平台关机充电动画横屏显示修改

问题背景 在Android R的系统rom定制化开发中,在关于展讯平台的产品中,系统默认的充电动画是竖屏显示的,但是在像平板的产品中竖屏动画肯定不符合规范, 所以需要在平板TV产品中,充电动画同时也是需要修改为横屏显示的,接下来就来分析下充电动画的相关绘制流程,然后实现功…

INSERT INTO B SELECT A

insert into B (key, province, city, district, name, address, price_low, price_high, beds, property, type) select (key, province, city, district, name, address, price_low, price_high, beds, property, type) from A where is_donetrue and address!地址&#xf…

【投稿优惠-EI稳定检索】2024年人工智能、自然语言处理与机器学习国际会议(ICAINLPML 2024)

2024 International Conference on Artificial Intelligence, Natural Language Processing and Machine Learning (ICAINLPML 2024) 网址&#xff1a;www.icainlpml.com 邮箱: ainlpmlsub-conf.com ●会议简介 2024年人工智能、自然语言处理与机器学习国际会议将邀请全球人…

Jackson 2.x 系列【24】Spring Web 集成

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Jackson 版本 2.17.0 源码地址&#xff1a;https://gitee.com/pearl-organization/study-jaskson-demo 文章目录 1. 前言2. Spring Web3. Jackson2ObjectMapperBuilder4. Jackson2ObjectMapperFa…

比例控制器H5773282、H8135950、H3390627、H6079948

名称&#xff1a;BEUEC数字比例放大器、伺服比例控制器、伺服比例阀放大板&#xff0c;订货代号&#xff1a;H5773282、H8135950、H3390627、H6079948、H6108848、H6700353、H8851035、H1688388、H9549313、H3264103、H1182967&#xff0c;输入指令可选10V、4-20mA&#xff0c;…

Session缓存、Hibernate处理对象的状态了解

Session接口 Session接口是Hibernate向应用程序提供的操纵数据库的最主要的接口&#xff0c;它提供了基本的保存&#xff0c;更新&#xff0c;删除和查询的方法。 Session是有一个缓存, 又叫Hibernate的一级缓存 session缓存是由一系列的Java集合构成的。当一个对象被加入到…

[大模型]Atom-7B-Chat 接入langchain搭建知识库助手

Atom-7B-Chat 接入langchain搭建知识库助手 环境准备 在autodl平台中租一个3090等24G显存的显卡机器&#xff0c;如下图所示镜像选择PyTorch–>2.0.0–>3.8(ubuntu20.04)–>11.8 接下来打开刚刚租用服务器的JupyterLab&#xff0c;并且打开其中的终端开始环境配置…

Linux 网络测速

1.开发背景 网络测速&#xff0c;为了测试开发板的网络速度是否达标的通用测试方法 2.开发需求 搭建 iperf3 &#xff0c;在 ubuntu 下安装服务端&#xff0c;在板卡上安装客户端&#xff0c;服务端和客户端互发 3.开发环境 ubuntu20.04 嵌入式开发板&#xff08;debian 千…

LeetCode_丑数

题目&#xff1a; 题解&#xff1a; 由题&#xff0c;我们知道丑数大于0&#xff0c;丑数都可以写成2*2*...*2*3*3...*3*5*5...*5&#xff0c;有了这个基础就很好写代码了。 用三个while循环将前面的2 3 5全部除掉如果这个数是丑数&#xff0c;最后n是等于1的&#xff0c;反之…

C++_第五周做题总结_构造与析构

id:31 A.Point&#xff08;类与构造&#xff09; 题目描述 下面是一个平面上的点的类定义&#xff0c;请在类外实现它的所有方法&#xff0c;并生成点测试它。 class Point {double x, y; public:Point(); // 缺省构造函数&#xff0c;给x,y分别赋值为0Point(double x_value…

nvm node.js的安装

说明&#xff1a;部分但不全面的记录 因为过程中没有截图&#xff0c;仅用于自己的学习与总结 过程中借鉴的优秀博客 可以参考 1,npm install 或者npm init vuelatest报错 2&#xff0c;了解后 发现是nvm使用的版本较低&#xff0c;于是涉及nvm卸载 重新下载最新版本的nvm 2…

激光雷达初识

一、实车激光雷达 一般在车顶位置: 二、激光雷达组成 激光收发器模块:发射激光器VCSEL+接收模块采用了SiPM(硅基光电倍增管)或者APD,一个激光器发生失效的情况,其他仍可正常工作 扫描模块:水平视场和的垂直视场的扫描,128个阵列的VCSEL激光器负责 信号处理模块:信号处…