C++右值引用与move和forward函数的使用详解
作者:Maxwell.. 发布时间:2023-07-05 19:27:33
1、右值
1.1 简介
首先区分一下左右值:
左值是指存储在内存中、有明确存储地址(可取地址)的数据;
右值是指可以提供数据值的数据(不可取地址)
如int a=123;123是右值, a是左值。总的来说 可以对表达式取地址(&)就是左值,否则为右值
而C++11 中右值又可以分为两种:
纯右值:非引用返回的临时变量、运算表达式产生的临时变量如a+b、原始字面量和 lambda 表达式等
将亡值:与右值引用相关的表达式、返回T&& 类型函数的返回值
1.2 右值引用
常见的 & 为左值引用、右值引用使用 && 表示
int&& a = 123;
int &b = a;
int &&c = a;//不合法
如上 a 是对123的右值引用,但是a本身是左值,其在内存中有明确的存储地址,所以c不能再对其进行左值引用。
1.3 右值引用的意义
可以将资源(堆、系统对象等)通过浅拷贝从一个对象转移到另一个对象这样就能减少不必要的临时对象的创建、拷贝以及销毁,可以大幅提高应用程序的性能。
#include <iostream>
using namespace std;
class Test
{
public:
Test() : num(new int(100))
{
cout << "construct" << endl;
}
Test(const Test& a) : num(new int(*a.num))
{
cout << "copy construct" << endl;
}
// 移动构造函数其实就是将入参的资源赋值给自己,并将入参的对应资源指针制空,
Test(Test&& a) : num(a.num)
{
cout << "rv copy construct" << endl;
a.num = nullptr;
}
~Test()
{
delete num;
}
int* num;
};
Test getObj()
{
Test t;
return t;
}
int main()
{
Test t = getObj();
return 0;
};
getObj()会得到一个非引用的临时对象,是纯右值,如果只有拷贝构造函数就只能再次new一块区域去保存该右值的资源,这是因为不能确定拷贝构造传入的参数后面是不是还会继续被使用, 只好进行深拷贝。而对于传入右值的情况,可以确定右值以后不会再进行访问,因此可直接将其指针复给新对象,将入参的对应指针置为null,防止析构造成野指针,避免深拷贝带来的性能消耗。
由此可见,右值引用具有移动语义:将确定后续不再使用的对象中的资源转移给新的对象,虽然左值引用也能够做到资源转移,但传入的左值后续可能还会被更改和使用,个人认为右值引用恰好做到了这种区分。
2、move
使用std::move方法可以将左值转换为右值。使用这个函数并不能移动任何东西,而是和移动构造函数一样都具有移动语义,将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存拷贝。
当确定一个变量a后续不会再进行使用,并且需要将其赋值给另一个对象时,可以使用移动构造来转移资源
Test a;
Test && b = a; // error
上面的操作是不可行的,因为a不是一个右值,要想调用Test的移动构造函数,就必须将a这个左值转变为一个右值:使用move() 函数
Test a;
Test && b = move(a); // ok
std::move 基本等同于一个类型转换:
static_cast<T&&>(lvalue)
3、foward
move将左值转换为右值,foward可以满足更多的情形
std::forward<T>(t);
当T为左值引用类型时,t将被转换为T类型的左值
当T不是左值引用类型时,t将被转换为T类型的右值
int a = 123;
foward<int&>(a); // a转换为左值并返回
foward<int&&>(a); // a转换为右值并返回
foward<int>(a); // a转换为右值并返回
来源:https://blog.csdn.net/ulan420/article/details/126363446
猜你喜欢
- 这篇文章主要介绍了Spring自动装配Bean实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要
- LINQ查询表达式的基本语法很容易掌握,它使用C#常见的语言构造,从外观上看,和我们常用的SQL类似,并且查询表达式中的变量可以用匿名类型,
- 前言总结java常见的锁区分各个锁机制以及如何使用使用方法锁名考察线程是否要锁住同步资源乐观锁和悲观锁锁住同步资源后,要不要阻塞不阻塞可以使
- AntPathMatcher前言(1)SpringMVC的路径匹配规则是依照Ant的来的,实际上不只是SpringMVC,整个Spring框
- android开发中通过View的getDrawingCache方法可以达到截屏的目的,只是缺少状态栏!原始界面截屏得到的图片代码实现1.
- 开发过程中经常用到加载圈,特别是车机开发由于外设不同很多操作响应的等待时长经常要用到不同的加载圈。首先,直接上菊花效果图,这是我直接从项目里
- 需要记录日志的地方包括:进入方法的时候,传参的时候,统计执行时间,方法返回参数的时候,退出语句块的时候,出现异常的时候,等等。先来体验不使用
- 话不多说,请看代码:public Map<String, Object> getWeeklyBySearch(final Map
- 关于用户token处理到的坑当采用前后台完全分离,以微服务架构的搭建时。在搭建微服务过程中,由于每个服务都是独立的应用,这样就会造成一个统一
- 一、JdbcTemplateSpring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作二、实战2.1 引
- Java IO BufferedInputStream概要:BufferedInputStream是缓冲输入流,继承于Filte
- 本文主要介绍了Spring Boot 应用可视化监控,分享给大家,具体如下:1、Spring Boot 应用暴露监控指标【版本 1.5.7.
- 1.概述数据库开发一直是JAVA开发的核心之一,作为现在JAVA EE的基石框架,Spring Boot自身携带了一个JDBCTemplat
- 本文实例讲述了java实现一次性压缩多个文件到zip中的方法。分享给大家供大家参考,具体如下:1.需要引入包:import java.io.
- 布局文件activity_main.xml<RelativeLayout xmlns:android="http://sch
- //1.创建数据库public class DBService extends SQLiteOpenHelper {private fina
- 本文实例讲述了C#中const用法。分享给大家供大家参考。具体用法分析如下:const是一个c语言的关键字,它限定一个变量不允许被改变。使用
- 引言在unity中可以将不同场景的背景和道具放置在不同的Scene当中,通过对Scene的加载和卸载来实现场景之间的切换。同时创建一个基础场
- 话说2016年的直播比较火,2017年短视频又火了。但对于开发者来说隐藏在这背后的技术才是我们所关心的,毕竟我们是靠技术吃饭的。现在在安卓中
- 上篇文章给大家介绍了在idea中将创建的java web项目部署到Tomcat中的过程图文详解,可以参考下,本文给大家继续介绍如何在IDEA