首页 > 其他分享 >转移和完美转发

转移和完美转发

时间:2023-12-05 13:55:05浏览次数:27  
标签:右值 完美 move 左值 printValue 转发 forward 实参 转移

文章参考:

爱编程的大丙 (subingwen.cn)

1. move

作用:主要作用有两点:

  • 实现用左值来初始化右值引用。
  • 进行对象间的资源转移。(避免使用拷贝,从而提高效率)

特点:

  • 可以将左值转化为右值。
  • 该函数和移动构造函数一样,都有移动语义,将对象的状态或者所有权从一个对象转移到另一个对象,且进行内存拷贝。

原型:从实现上看,std::move()基类等同于一个类型转移static_cast<T&&>(lvalue)

template <class _Ty>
_NODISCARD constexr remove_reference_t<_Ty>&& move(_Ty&& _Arg) _NOEXCEPT{
    return static_cast<remove_reference_t<_Ty>&&> (_Arg));
}

Eg:

  • 用左值来初始化右值引用

    #include <iostream>
    class Test {
    public: 
        Test(){}
    };
    
    int main(void){
        Test t;				
        Test& lt = t;
        Test&& rt = std::move(t);		
        return 0;
    }
    
    • t是左值,但通过std::move(),可以用左值对右值引用进行初始化。
  • 实现对象间的资源转移,无需复制:

    #include <iostream>
    #include <list>
    using namespace std;
    
    int main(void){
        list<int> l1 = {1, 2, 3, 4, 5};
        list<int> l2 = move(l1);
        cout << "l1:";
        for(auto t: l1){
            cout << t << " ";
        }
        cout<<endl;
        cout << "l2:";
        for(auto t : l2){
            cout << t << " ";
        }
        cout << endl;
        return 0;
    }
    
    • 输出:

      l1:
      l2:1 2 3 4 5 
      
    • 分析:因为使用了std::move(),列表l1的资源被转移给了列表l2,因此列表l1没有资源了。

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类型的右值。

EG:

  • 代码:

    #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);
        int num = 1314;
        testForward(num);
        testForward(forward<int>(num));
        testForward(forward<int&>(num));
        testForward(forward<int&&>(num));
    
        return 0;
    }
    
  • 输出:

    l-value: 520
    r-value: 520
    r-value: 520
    
    l-value: 1314
    r-value: 1314
    l-value: 1314
    
    l-value: 1314
    r-value: 1314
    r-value: 1314
      
    l-value: 1314
    r-value: 1314
    l-value: 1314
        
    l-value: 1314
    r-value: 1314
    r-value: 1314
    
  • 分析:

    • testForward(520):函数形参T&&为未定义引用类型,实参为右值,初始化后被推导为一个右值引用。
      • printValue(v):已命名的右值v,编译器会视作左值处理,因此实参是左值
      • printValue(move(v)):已命名的右值被编译器视作左值处理,随后又通过move转换为右值,因此实参是右值
      • printValue(forward<T>(v)):已命名的右值被编译器视作左值处理,而此处的模板参数T为右值引用,因此参数被完美转发成一个右值,因此实参是右值
    • testForward(num):函数形参T&&为未定义引用类型,实参为左值,初始化后被推导为一个左值引用。
      • printValue(v):实参是左值
      • printValue(move(v)):左值通过move转换为右值,因此实参是右值
      • printValue(forward<T>(v)):forward的模板参数为左值引用,最终得到一个左值引用,实参为左值
    • testForward(forward<int>(num)):forward的模板参数不是左值引用,因此num被完美转发为右值,函数形参T&&为未定义引用类型,最终实参为右值
      • printValue(v):已命名的右值v,编译器会视作左值处理,因此实参是左值
      • printValue(move(v)):已命名的右值被编译器视作左值处理,随后又通过move转换为右值,因此实参是右值
      • printValue(forward<T>(v)):已命名的右值被编译器视作左值处理,而此处的模板参数T为右值引用,因此参数被完美转发成一个右值,因此实参是右值
    • testForward(forward<int&>(num)):forward的模板参数int&是左值引用,因此num被完美转发为左值,函数形参T&&为未定义引用类型,最终实参为左值
      • printValue(v):实参是左值
      • printValue(move(v)):左值通过move转换为右值,因此实参是右值
      • printValue(forward<T>(v)):forward的模板参数为左值引用,最终得到一个左值引用,实参为左值
    • testForward(forward<int&&>(num)):forward的模板参数int&&不是左值引用,因此num被完美转发为右值,函数形参T&&为未定义引用类型,最终实参为
      • printValue(v):已命名的右值v,编译器会视作左值处理,因此实参是左值
      • printValue(move(v)):已命名的右值被编译器视作左值处理,随后又通过move转换为右值,因此实参是右值
      • printValue(forward<T>(v)):已命名的右值被编译器视作左值处理,而此处的模板参数T为右值引用,因此参数被完美转发成一个右值,因此实参是右值

标签:右值,完美,move,左值,printValue,转发,forward,实参,转移
From: https://www.cnblogs.com/beasts777/p/17877053.html

相关文章

  • #yyds干货盘点# LeetCode程序员面试金典:完美数
    题目对于一个正整数,如果它和除了它自身以外的所有正因子之和相等,我们称它为「完美数」。给定一个整数n,如果是完美数,返回true;否则返回false。 示例1:输入:num=28输出:true解释:28=1+2+4+7+141,2,4,7,和14是28的所有正因子。示例2:输入:num=7......
  • 华为云IotDA平台与OBS进行数据转发并使用ECS服务器完成数据调用
    华为云IotDA平台与OBS进行数据转发并使用ECS服务器完成数据调用一、通过IotDA平台接入物联网设备参考博客:https://www.cnblogs.com/gitcatone/p/17796975.html二、注册ECS服务器并进行远程控制产品简介ECS弹性服务器,一款运行在云端的弹性虚拟计算机,能够实现弹性储存容量与......
  • 【C++ Primer Plus】C++11 深入理解右值、右值引用和完美转发
    1.右值引用和移动语义1.1左值和右值左值localvalue:存储在内存中、有明确存储地址(可寻址)的数据(x、y、z)右值 readvalue:不一定可以寻址,例如存储于寄存器中的数据;通常字面量都是右值,除了字符串常量(1、3)intx=1;inty=3;intz=x+y; 对于x++和++x虽然都是自......
  • Applescript实现无痕检测手机号或邮箱号是否注册iMessage服务,iMessage蓝号检测完美实
    一、检测数据的两种方式:1.人工筛选,将要验证的号码输出到文件中,以逗号分隔。再将文件中的号码粘贴到iMessage客户端的地址栏,iMessage客户端会自动逐个检验该号码是否为iMessage账号,检验速度视网速而定。红色表示不是iMessage账号,蓝色表示iMessage账号。2.编写脚本控制Macos/iphon......
  • 汽车托运如何完美避坑
    在现代社会中,汽车托运已经成为了一种常见的服务。无论是因为搬家、旅游还是其他原因,许多人都会选择将汽车托运到目的地。然而,由于市场上的服务质量参差不齐,很多人在托运过程中遇到了各种问题,甚至有些人因此遭受了损失。那么,如何在汽车托运过程中避免掉入这些“坑”呢?以下是一些实......
  • 团聚美味:打造完美火锅聚餐
    美味火锅:快速准备与愉快用餐引言准备一顿美味的火锅聚餐需要仔细策划和高效的组织。在这篇博客中,我们将讨论从购物清单、提前准备、人员协作到火锅方案等各个方面的建议,同时考虑到特殊情况。购物清单主食建议:肉类:约500克牛肉片、300克羊肉片、300克鸡肉片等。海鲜:约400克鲜......
  • 马尔可夫Markov区制转移模型分析基金利率|附代码数据
    全文下载链接:http://tecdat.cn/?p=19611最近我们被客户要求撰写关于马尔可夫Markov区制转移模型的研究报告,包括一些图形和统计输出。过程会随着时间的推移而发展,结果会发生变化考虑一下经济衰退和扩张。在衰退开始时,产出和就业率下降并保持较低水平,然后,产出和就业率增加。从统......
  • C++完美开发环境vscode+clangd+lldb+xmake(已亲测有效,使用体验秒杀vscode官方C++插件)
    vscode下载并安装1.下载vscode官网下载网速不好的可以在这里自取:vscode蓝奏云下载密码:hnp42.安装选择我同意可以选择不创建开始菜单这里勾选了最后一个选择(添加到系统环境变量中,如果没有勾选这个选项,则需要手动添加),其他的按自己情况勾选,建议全部勾选方便使用安装......
  • Spring配置文件的魔法炼金术:如何制造容器化时代的完美配方
    前言基于现代服务的云原生十二要素理论,我们在采用容器化部署时,要保证同一个镜像可以满足不同环境的部署要求,而不是不同环境打包不同的镜像。本文档主要介绍一种基于spring框架的满足不同环境配置的编译打包方案,满足同一个镜像可以在环境分组下通过启动项配置实现不同环境的部署。......
  • 如何正确的在AIX 7上正确开启大页内存(large page)on oracle 11.2.0.4 rac 转发 https:
    1、关于大页有个客户的业务系统上要开启大页,提高系统性能,研究了一下,网上文章太多,自己做了一些测试,经过实机测试,整理了一下操作记录。关于AIX上为什么要开启大页,借用MOS里的说明原文:StartingwiththeAIXV5.1operatingsystemwhenrunningonIBMPOWER4orPOWER5proces......