c++ std::move 和 std::forward

  • 在C++11标准之前,C++中默认的传值类型均为Copy语义,即:不论是指针类型还是值类型,都将会在进行函数调用时被完整的复制一份。所以引入了move和forward
临时值(右值)简述
func("some temporary string"); // 尽管直接将一个常量传入函数中, C++还是大概率会创建一个string的复制
v.push_back(X()); // 初始化了一个临时X, 然后被复制进了vector
a = b + c; // b+c是一个临时值, 然后被赋值给了a
x++; // x++操作也有临时变量的产生(++x则不会产生)
a = b + c + d; //c+d是一个临时变量, b+(c+d)是另一个临时变量vector<string> str_split(const string& s) {vector<string> v;// ...return v; // v是左值,但优先移动,不支持移动时仍可复制
}
使用 move
// Copy constructor
MyString(const MyString &str) {}
// Move constructor
MyString(MyString &&str) noexcept {}
// Copy assignment
MyString& operator=(const MyString& str) {}
// Move assignment
MyString& operator=(MyString&& str) {}//使用std::move
void f_move(Object &&obj) {}
Object(Object &&object) noexcept: _str(std::move(object._str)) {}
  1. 实际上,C++中的move函数只是做了类型转换,并不会真正的实现值的移动,因此对于自定义的类来说,如果要实现真正意义上的 “移动”,还是要手动重载移动构造函数和移动复制函数。即:我们需要在自己的类中实现移动语义,避免深拷贝,充分利用右值引用和std::move的语言特性。
  2. 通常情况下C++编译器会默认在用户自定义的class和struct中生成移动语义函数。但前提是:用户没有主动定义该类的拷贝构造等函数!
  3. 如果我们没有提供移动构造函数,只提供了拷贝构造函数,std::move()会失效但是不会发生错误,因为编译器找不到移动构造函数就去寻找拷贝构造函数,这也是拷贝构造函数的参数是const T&常量左值引用的原因
  4. c++11中的所有容器都实现了move语义,move只是转移了资源的控制权,本质上是将左值强制转化为右值使用,以用于移动拷贝或赋值,避免对含有资源的对象发生无谓的拷贝
  5. move对于拥有如内存、文件句柄等资源的成员的对象有效,如果是一些基本类型,如int和char[10]数组等,如果使用move,仍会发生拷贝(因为没有对应的移动构造函数),所以说move对含有资源的对象说更有意义。
foward 向前的,前进的;

完美转发是指在函数模板中,完全依照模板的参数的类型,将参数传递给函数模板中调用的另 一个函数,即传入转发函数的是左值对象,目标函数就能获得左值对象,转发函数是右值对象, 目标函数就能获得右值对象,而不产生额外的开销。

  1. 什么是foward?

    1. 问题:使用move后,处理临时变量用右值引用T&&,处理普通变量用const引用const T&,需要分别建立两个函数,然后入参使用不同的类型,每个函数都要写两遍。
    2. 能不能将T &&类型和const T &类型合二为一呢?
  2. std::forward也被称为完美转发,即:保持原来的值属性不变:

    1. 如果原来的值是左值,经std::forward处理后该值还是左值。如果外面传来了左值,它就转发左值并且启用copy,同时它也还能保留const。
    2. 如果原来的值是右值,经std::forward处理后它还是右值。如果外面传来了右值临时变量,它就转发右值并且启用move语义。

这样一来,我们就可以使用forward函数对入参进行封装,从而保证了入参的统一性,从而可以实现一个方法处理两种类型!
正因为如此,forward函数被大量用在了入参值类型情况不确定的C++模板中!

template<typename T>
void f_forward(T &&t) {Object a = std::forward<T>(t);//调用了std::forward<T>(t)来创建一个新的对象。std::cout << "forward this object, address: " << &a << std::endl;
}int main() {Object obj{"abc"};//分别使用一个左值和一个右值调用了该模板函数。f_forward(obj);f_forward(Object("def"));return 0;
}build this object, address: 000000CFAE8FFC78
copy this object, address: 000000CFAE8FFBD8
forward this object, address: 000000CFAE8FFBD8
destruct this object, address: 000000CFAE8FFBD8
build this object, address: 000000CFAE8FFCB8
move this object!
forward this object, address: 000000CFAE8FFBD8
destruct this object, address: 000000CFAE8FFBD8
destruct this object, address: 000000CFAE8FFCB8
destruct this object, address: 000000CFAE8FFC78
move和forward函数的区别
  1. 基本上forward可以cover所有的需要move的场景,毕竟forward函数左右值通吃
  2. 那为什么还要使用move呢?原因主要有两点:
    1. 首先,forward函数常用于模板函数这种入参情况不确定的场景中,在使用的时候必须要多带一个模板参数forward,代码略复杂
    2. 此外,明确只需要move临时值的情况下如果使用了forward,会导致代码意图不清晰,其他人看着理解起来比较费劲

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

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

相关文章

堆栈与堆(Stack vs Heap)有什么区别?

​编写有效的代码需要了解堆栈和堆内存&#xff0c;这使其成为学习编程的重要组成部分。不仅如此&#xff0c;新程序员或职场老手都应该完全熟悉堆栈内存和堆内存之间的区别&#xff0c;以便编写有效且优化的代码。 这篇博文将对这两种内存分配技术进行全面的比较。通过本文的…

Asp.net core api http请求是怎么找到对应方法并参数映射的

在ASP.NET Core中&#xff0c;HTTP请求是通过路由系统找到对应的方法&#xff0c;并将请求的参数映射到方法的参数上。具体的过程如下&#xff1a; 路由系统&#xff1a; ASP.NET Core中的路由系统负责处理传入的HTTP请求&#xff0c;并根据请求的路径和其他条件决定将请求发送…

网络协议--链路层

2.1 引言 从图1-4中可以看出&#xff0c;在TCP/IP协议族中&#xff0c;链路层主要有三个目的&#xff1a; &#xff08;1&#xff09;为IP模块发送和接收IP数据报&#xff1b; &#xff08;2&#xff09;为ARP模块发送ARP请求和接收ARP应答&#xff1b; &#xff08;3&#xf…

电子元器件数量BOM表统计

在我们绘制完电路原理图或PCB板图后需要输出每个元器件&#xff0c;但是绘图软件上器件名称&#xff0c;数值&#xff0c;模本不是跟理想的一样&#xff0c;BOM表输出还有根据自己的公司规制重新命名&#xff0c;有时根据&#xff0c;常用的位标就是R&#xff0c;C&#xff0c;…

java操作文件,生成文件,读取文件,按顺序读取文件

按顺序读取文件名 Arrays.sort()方法对文件数组进行排序&#xff0c;然后按照排序后的顺序遍历文件数组&#xff0c;以按照文件名从大到小的顺序展示文件名 public class FileSortExample {public static void main(String[] args) {File directory new File("path/to/…

Linux文件系统及命令 | 实用操作指令汇总

目录 ctrl c 强制停止与ctrl d 退出或登出 history&#xff1a;历史命令搜索 clear:清屏 ln命令&#xff1a;创建软硬连接 cat命令&#xff1a;显示文件命令 less命令&#xff1a;查看大文件 grep命令&#xff1a;正则表达式使用 sort命令&#xff1a;排序 uniq命令…

JSON的MIME媒体类型是application/json

JSON&#xff08;全称 JavaScript Object Notation&#xff09;即JavaScript对象表示法&#xff0c;通知使用application/json媒体类型。 目录 1、JSON介绍 2、JSON语法 3、实践总结 运行环境&#xff1a; Windows-7-Ultimate-x64、Windows-10-BusinessEditions-21h2-x64 1…

闲话Python编程-字典dict

在我的Python编程经历中&#xff0c;Python有两大最常用的数据结构&#xff1a;列表list和字典dict&#xff0c;搞明白了这两个数据结构的所有知识点&#xff0c;日常编程基本不成问题了。列表list在前面专题已经详细讲过&#xff0c;本章来着重讲解字典dict的用法。 1. 定义与…

区块链实验室(27) - 区块链+物联网应用案例

分享最新的区块链物联网应用案例&#xff1a;HPCLS-BC

【Kafka专题】Kafka快速实战以及基本原理详解

目录 前言课程内容一、Kafka介绍1.1 MQ的作用1.2 为什么用Kafka 二、Kafka快速上手2.1 实验环境2.2 单机服务体验2.3 认识Kafka模型架构2.4 Kafka集群2.5 理解服务端的Topic、Partion和Broker2.6 章节总结&#xff1a;Kafka集群的整体结构 三、Kraft集群&#xff08;拓展&#…

集群-Nacos-2.2.3、Nginx-1.24.0集群配置

Nacos集群 高可用 Nginx 集群Nacos 集群&#xff08;至少三个实例&#xff09;高可用数据库集群&#xff08;取代 Nacos 内嵌数据库&#xff09; Nacos 集群搭建 集群使用版本&#xff1a; Nginx 1.24.0 Nacos 2.2.3 服务器IP服务器版本Nginx18.18.18.40CentOS-7.9MySQL18.18.…

【计算机网络笔记七】应用层(四)HTTP 通过Content-Type提交数据的方式

1. Content-Type: application/x-www-form-urlencoded 表示纯文本表单提交方式 格式如下&#xff1a; POST /users HTTP/1.1 Host: api.github.com Content-Type: application/x-www-form-urlencoded Content-Length: 27namezhangsan&gendermale 对应的 Retrofit 代码:…

如何安装并启动jupyter notebook

jupyter是什么 Jupyter Notebook 可以使用多种语言&#xff08;Python、R、Julia 等&#xff09;开发交互式笔记本&#xff0c;因此&#xff0c;它会依赖于不同的包和库。但是&#xff0c;对于 Jupyter Notebook 的 Python 版本&#xff0c;以下是一些主要的依赖项&#xff1a…

样品运输与贮存

声明 本文是学习GB-T 42959-2023 饲料微生物检验 采样. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本文件规定了以微生物检验为目的的采样原则、采样人员、设备和材料、采样方案、采样步骤和采样 报告。 本文件适用于以微生物检验为目的…

flutter开发实战-webview插件flutter_inappwebview使用

flutter开发实战-webview插件flutter_inappwebview使用 在开发过程中&#xff0c;经常遇到需要使用WebView&#xff0c;Webview需要调用原生的插件来实现。常见的flutter的webview插件是webview_flutter&#xff0c;flutter_inappwebview。之前整理了一下webview_flutter&…

手机投屏到笔记本电脑小方法

1、我们可以开启Windows自带的投影功能&#xff0c;将我们的手机和电脑连接同一个无线网络。 2、在电脑开始菜单栏里找到设置选项并打开。 3、我们进入之后找到系统选项&#xff0c;点击进去之后找到点击投影到这台电脑&#xff0c;接下来我们将默认的始终关闭的下拉选项更改为…

国庆作业6

TCP服务器 #include "head.h" #define PORT 2580 //端口号 #define IP "192.168.31.219" //本机IP int main(int argc, const char *argv[]) {sqlite3* dbNULL;if(sqlite3_open("./my.db",&db)!SQLITE_OK){fprintf(stde…

257. 二叉树的所有路径

257. 二叉树的所有路径 原题 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode…

OpenGl材质

在现实世界里,每个物体会对光产生不同的反应。比如,钢制物体看起来通常会比陶土花瓶更闪闪发光,一个木头箱子也不会与一个钢制箱子反射同样程度的光。有些物体反射光的时候不会有太多的散射(Scatter),因而产生较小的高光点,而有些物体则会散射很多,产生一个有着更大半径的…

python 使用 scapy 扫描内网IP或端口

地址信息在IP层, 可以利用 ICMP 或 ARP 协议数据包探测IP信息. ICMP协议可以利用ping工具发送数据包, 但是防火墙有可能禁止ICMP, 无法有效探测, 可以考虑使用ARP探测. 利用ICMP协议探测内网IP def ping_ip(ip_fex):# 扫描范围: 128~254for i in range(128, 255):ip f{ip_fe…