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

目录
  • 1、右值
    • 1.1 简介
    • 1.2 右值引用
    • 1.3 右值引用的意义
  • 2、move
  • 3、foward

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++右值引用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 一文搞懂C++11万能引用和右值引用

    目录 前言 正文 万能引用 结语 参考: 前言 我们通过一个问题来进入今天的话题:1.形如 “type&&” 的结构,就是右值引用吗?2.以下哪些属于右值引用? ① void fun(Widget && param);② Widget && var1= Widget();③ auto && var2 = var1;④ template<typename T> void f(std::vector<T>&&

  • 一篇文章弄懂C++左值引用和右值引用

    目录 1. 左值和右值 2. 左值引用 3. 右值引用 3.1 出现 3.2 概念 3.3 应用 3.3.1 右值引用绑定到左值上 3.3.2 std::move()本质 3.3.3 移动构造函数和移动赋值运算符 3.3.4 std::move()的一个例子 4. 补充-协助完成返回值优化(RVO) 5. 总结 篇幅较长,算是从0开始介绍的,请耐心看~ 该篇介绍了左值和右值的区别.左值引用的概念.右值引用的概念.std::move()的本质.移动构造函数.移动复制运算符和RVO. 1. 左值和右

  • 详解C++右值引用

    概述 在C++中,常量.变量或表达式一定是左值(lvalue)或右值(rvalue). 左值:非临时的(具名的,可在多条语句中使用,可以被取地址).可以出现在等号的左边或右边.可分为非常量左值和常量左值. 右值:临时的(不具名的,只在当前语句中有效,不能取地址).只能出现在等号的右边.可分为非常量右值和常量右值. 左值引用:对左值的引用就是左值引用.可分为非常量左值引用和常量左值引用. 注:常量左值引用是"万能"的引用类型,可以绑定到所有类型的值,包括非常量左值.常量左值.非常量右值和

  • C++11中std::move、std::forward、左右值引用、移动构造函数的测试问题

    关于C++11新特性之std::move.std::forward.左右值引用网上资料已经很多了,我主要针对测试性能做一个测试,梳理一下这些逻辑,首先,左值比较熟悉,右值就是临时变量,意味着使用一次就不会再被使用了.针对这两种值引入了左值引用和右值引用,以及引用折叠的概念. 1.右值引用的举例测试 #include <iostream> using namespace std; ​ //创建一个测试类 class A { public: A() : m_a(55) { } ​ int m_a;

  • C++11语法之右值引用的示例讲解

    目录 一.{}的扩展 initializer_list的讲解: 跳转initializer_list实现 二.C++11一些小的更新 decltype nullptr 范围for 新容器 三.右值引用 右值真正的用法 完美转发 默认成员函数 总结 一.{}的扩展 在原先c++的基础上,C++11扩展了很多初始化的方法. #include<iostream> using namespace std; struct A { int _x; int _y; }; int main() int a[]

  • C++精要分析右值引用与完美转发的应用

    目录 区分左值与右值 右值引用 移动语义 完美转发 结语 区分左值与右值 在C++面试的时候,有一个看起来似乎挺简单的问题,却总可以挖出坑来,就是问:“如何区分左值与右值?” 如果面试者自信地回答:“简单来说,等号左边的就是左值,等号右边的就是右值.” 那么好了,手写一道面试题继续提问. int a=1; int b=a; 问:a和b各是左值还是右值? b是左值没有疑问,但如果说a在上面是左值,在下面是右值的,那就要面壁思过了.C++从来就不是一门可以浅尝辄止的编程语言,要学好它真的需要不断地去

  • 聊聊C++中右值引用和移动构造函数的使用

    目录 一: 背景 二: 右值引用 1. 它到底解决了什么问题 2. 右值引用是个什么样子 三: 右值引用如何减少对象的创建 1. 简要思路 2. 一个简单的例子 3. 性能优化方案 四: 总结 一: 背景 最近在看 C++ 的右值引用和移动构造函数,感觉这东西一时半会还挺难理解的,可能是没踩过这方面的坑,所以没有那么大的深有体会,不管怎么说,这一篇我试着聊一下. 二: 右值引用 1. 它到底解决了什么问题 在其他编程语言中,很少听到 右值引用 这个词,我个人感觉还是 C++ 这个 值类型 优先的

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

    目录 1.右值 1.1 简介 1.2 右值引用 1.3 右值引用的意义 2.move 3.foward 1.右值 1.1 简介 首先区分一下左右值: 左值是指存储在内存中.有明确存储地址(可取地址)的数据: 右值是指可以提供数据值的数据(不可取地址) 如int a=123:123是右值, a是左值.总的来说 可以对表达式取地址(&)就是左值,否则为右值 而C++11 中右值又可以分为两种: 纯右值:非引用返回的临时变量.运算表达式产生的临时变量如a+b.原始字面量和 lambda 表达式等 将亡

  • C++11右值引用和转发型引用教程详解

    右值引用 为了解决移动语义及完美转发问题,C++11标准引入了右值引用(rvalue reference)这一重要的新概念.右值引用采用T&&这一语法形式,比传统的引用T&(如今被称作左值引用 lvalue reference)多一个&. 如果把经由T&&这一语法形式所产生的引用类型都叫做右值引用,那么这种广义的右值引用又可分为以下三种类型: 无名右值引用 具名右值引用 转发型引用 无名右值引用和具名右值引用的引入主要是为了解决移动语义问题. 转发型引用的引

  • 深入了解c++11 移动语义与右值引用

    1.移动语义 C++11新标准中一个最主要的特性就是提供了移动而非拷贝对象的能力.如此做的好处就是,在某些情况下,对象拷贝后就立即被销毁了,此时如果移动而非拷贝对象会大幅提升性能.参考如下程序: //moveobj.cpp #include <iostream> #include <vector> using namespace std; class Obj { public: Obj(){cout <<"create obj" << e

  • C++左值与右值,右值引用,移动语义与完美转发详解

    目录 C++——左值与右值.右值引用.移动语义与完美转发 一.左值和右值的定义 二.如何判断一个表达式是左值还是右值(大多数场景) 三.C++右值引用 四.std::move()与移动语义 五. 完美转发 总结 C++——左值与右值.右值引用.移动语义与完美转发 在C++或者C语言中,一个表达式(可以是字面量.变量.对象.函数的返回值等)根据其使用场景不同,分为左值表达式和右值表达式. 一.左值和右值的定义 1.左值的英文为locator value,简写为lvalue,可意为存储在内存中.有明

  • C++右值引用与移动构造函数基础与应用详解

    目录 1.右值引用 1.1左值右值的纯右值将亡值右值 1.2右值引用和左值引用 2.移动构造函数 2.1完美的移动转发 1.右值引用 右值引用是 C++11 引入的与 Lambda 表达式齐名的重要特性之一.它的引入解决了 C++ 中大量的历史遗留问题, 消除了诸如 std::vector.std::string 之类的额外开销, 也才使得函数对象容器 std::function 成为了可能. 1.1左值右值的纯右值将亡值右值 要弄明白右值引用到底是怎么一回事,必须要对左值和右值做一个明确的理解

  • C++标准之(ravalue reference) 右值引用介绍

    1.右值引用引入的背景 临时对象的产生和拷贝所带来的效率折损,一直是C++所为人诟病的问题.但是C++标准允许编译器对于临时对象的产生具有完全的自由度,从而发展出了CopyElision.RVO(包括NRVO)等编译器优化技术,它们可以防止某些情况下临时对象产生和拷贝.下面简单地介绍一下CopyElision.RVO,对此不感兴趣的可以直接跳过: (1)CopyElision CopyElision技术是为了防止某些不必要的临时对象产生和拷贝,例如: 复制代码 代码如下: structA{ A(

  • C++11右值引用和std::move语句实例解析(推荐)

    右值引用(及其支持的Move语意和完美转发)是C++0x将要加入的最重大语言特性之一.从实践角度讲,它能够完美解决C++中长久以来为人所诟病的临时对象效率问题.从语言本身讲,它健全了C++中的引用类型在左值右值方面的缺陷.从库设计者的角度讲,它给库设计者又带来了一把利器.从库使用者的角度讲,不动一兵一卒便可以获得"免费的"效率提升- 下面用实例来深入探讨右值引用. 1.什么是左值,什么是右值,简单说左值可以赋值,右值不可以赋值.以下面代码为例,"A a = getA();&q

  • 浅析C++11中的右值引用、转移语义和完美转发

    1. 左值与右值: C++对于左值和右值没有标准定义,但是有一个被广泛认同的说法:可以取地址的,有名字的,非临时的就是左值;不能取地址的,没有名字的,临时的就是右值. 可见立即数,函数返回的值等都是右值;而非匿名对象(包括变量),函数返回的引用,const对象等都是左值. 从本质上理解,创建和销毁由编译器幕后控制的,程序员只能确保在本行代码有效的,就是右值(包括立即数);而用户创建的,通过作用域规则可知其生存期的,就是左值(包括函数返回的局部变量的引用以及const对象),例如: int& fo

  • 深入解读C++中的右值引用

    右值引用(及其支持的Move语意和完美转发)是C++0x将要加入的最重大语言特性之一,这点从该特性的提案在C++ - State of the Evolution列表上高居榜首也可以看得出来. 从实践角度讲,它能够完美解决C++中长久以来为人所诟病的临时对象效率问题.从语言本身讲,它健全了C++中的引用类型在左值右值方面的缺陷.从库设计者的角度讲,它给库设计者又带来了一把利器.从库使用者的角度讲,不动一兵一卒便可以获得"免费的"效率提升- 在标准C++语言中,临时量(术语为右值,因其出

  • C++11 模板参数的“右值引用”是转发引用吗

    在C++11中,&&不再只有逻辑与的含义,还可能是右值引用: void f(int&& i); 但也不尽然,&&还可能是转发引用: template<typename T> void g(T&& obj); "转发引用"(forwarding reference)旧称"通用引用"(universal reference),它的"通用"之处在于你可以拿一个左值绑定给转发引用

随机推荐