C++右值引用与move和forward函数的使用详解

 更新时间:2022年08月19日 15:28:44   作者:Maxwell..  
为了支持移动操作,新标准引入了一种新的引用类型——右值引用(rvalue reference)。所谓右值引用就是必须绑定到右值的引用,这篇文章主要介绍了C++右值引用与move和forward的使用

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转换为右值并返回

到此这篇关于C++右值引用与move和forward函数的使用详解的文章就介绍到这了,更多相关C++右值引用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解C++ STL模拟实现forward_list

    详解C++ STL模拟实现forward_list

    forward_list是C++ 11新增的容器,它支持从容器中的任何位置快速插入和移除元素的容器,不支持快速随机访问。本文将模拟实现forward_list,感兴趣的可以了解一下
    2023-01-01
  • C++ 多态性虚函数和动态绑定学习笔记

    C++ 多态性虚函数和动态绑定学习笔记

    这篇文章主要为大家介绍了C++ 多态性虚函数和动态绑定学习笔记,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • C语言的数字游戏算法效率问题探讨实例

    C语言的数字游戏算法效率问题探讨实例

    这篇文章主要介绍了C语言的数字游戏算法效率问题探讨实例,需要的朋友可以参考下
    2014-04-04
  • VC中实现GB2312、BIG5、Unicode编码转换的方法

    VC中实现GB2312、BIG5、Unicode编码转换的方法

    这篇文章主要介绍了VC中实现GB2312、BIG5、Unicode编码转换的方法,该功能非常实用,需要的朋友可以参考下
    2014-07-07
  • C++实现高校人员信息管理系统

    C++实现高校人员信息管理系统

    这篇文章主要为大家详细介绍了C++实现高校人员信息管理系统项,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • C语言实现定时器控制LED灯闪烁

    C语言实现定时器控制LED灯闪烁

    这篇文章主要为大家详细介绍了C语言实现定时器控制LED灯闪烁,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-05-05
  • c++中strcpy函数在VS2015无法使用的问题

    c++中strcpy函数在VS2015无法使用的问题

    这篇文章主要介绍了c++中strcpy函数在VS2015无法使用的问题,具有一定的参考价值,有需要的可以了解一下。
    2016-11-11
  • C语言实现通讯录的详细代码

    C语言实现通讯录的详细代码

    本文详细讲解了C语言实现通讯录的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-12-12
  • 基于C语言实现学生管理系统

    基于C语言实现学生管理系统

    这篇文章主要为大家详细介绍了基于C语言实现学生管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • C++入门到精通之循环语句的使用教程

    C++入门到精通之循环语句的使用教程

    这篇文章主要给大家介绍了关于C++中循环语句的用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05

最新评论