当前位置: 首页 > article >正文

理解C++中的右值引用

右值引用,顾名思义,就是对一个右值进行引用,或者说给右值一个别名。右值引用的规则和左值一用一模一样,都是对一个值或者对象起个别名。

1. 右值引用和左值引用一样,在定义的同时必须立即赋值,如果不立即赋值,语法错误,看下面的例子

class A
{
    public:
    int m_val;
    A(int n):m_val(n) {    }
    A(A&& a)
    {
        m_val=a.m_val;
         cout<<"move constructor is called"<<endl;
    }
    A& operator=(const A&r)
    {
        if(this!=&r)
        {
            m_val=r.m_val;
            cout<<"move assignment operator is called"<<endl;
        }
    }
    ~A()
    {
        cout<<"Destructor is called"<<endl;
    }
};
int main(int argc, char const *argv[])
{
    A a(10);        //定一个对象(左值)
    A& lr=a;        //左值引用,同时赋值
    A&& rr=move(a);  //定义右值引用,同时赋值
    A&& rr2;        //定义右值引用,但是没有赋值
    rrw=move(a);    //非法
    return 0;
}

2. 右值引用的操作和左值引用一样,操作右值引用,就是操作源对象本身,因为右值引用就是源对象的一个别名。看下面的例子,操作左值引用、右值引用、源对象中的任何一个,其它两个都相应变化。

class A
{
    public:
    int m_val;
    A(int n):m_val(n) {    }
    A(A&& a)
    {
        m_val=a.m_val;
         cout<<"move constructor is called"<<endl;
    }
    A& operator=(const A&r)
    {
        if(this!=&r)
        {
            m_val=r.m_val;
            cout<<"move assignment operator is called"<<endl;
        }
    }
    ~A()
    {
        cout<<"Destructor is called"<<endl;
    }
};
int main(int argc, char const *argv[])
{
    A a(10);        //定一个对象(左值)
    A& lr=a;        //左值引用,同时赋值
    A&& rr=move(a);  //定义右值引用,同时赋值
    cout<<"lr.m_val="<<lr.m_val<<" "<<"rr.m_val="<<rr.m_val<<" "<<"a.m_val="<<a.m_val<<endl;
    cout<<"change value by original object"<<endl;
    a.m_val=20;
    cout<<"lr.m_val="<<lr.m_val<<" "<<"rr.m_val="<<rr.m_val<<" "<<"a.m_val="<<a.m_val<<endl;

    cout<<"change value  by left reference"<<endl;
    lr.m_val=30;
    cout<<"lr.m_val="<<lr.m_val<<" "<<"rr.m_val="<<rr.m_val<<" "<<"a.m_val="<<a.m_val<<endl;

    cout<<"change value  by right reference"<<endl;
    rr.m_val=40;
    cout<<"lr.m_val="<<lr.m_val<<" "<<"rr.m_val="<<rr.m_val<<" "<<"a.m_val="<<a.m_val<<endl;
    cout<<"left reference and right reference won't create any new object"<<endl;
    return 0;
}

输出结果如下:再次证明,引用就是起别名

3. 从上图可以看出,引用不会产生任何新的对象。

4. 右值引用和移动构造函数、移动赋值运算符没有任何关系。

5. 右值引用被正确赋值以后,还能被二次赋值,引用到一个新的对象上吗?不能。右值引用一旦被定义,随后的操作就对源对象的操作了。看下面这个例子:

class A
{
    public:
    int m_val;
    A(int n):m_val(n) {    }
    A(A&& a)
    {
        m_val=a.m_val;
         cout<<"move constructor is called"<<endl;
    }
    A& operator=(const A&r)
    {
        if(this!=&r)
        {
            m_val=r.m_val;
            cout<<"move assignment operator is called"<<endl;
        }
    }
    ~A()
    {
        cout<<"Destructor is called"<<endl;
    }
};
int main(int argc, char const *argv[])
{
    A a1(10);
    A a2(20);
    A&& rf=move(a1);

    rf=move(a2);        //不是对右值引用进行新的引用,而是等价为:a1=move(a2)
    cout<<"rf.m_val="<<rf.m_val<<"   "<<"a2.m_val= "<<a2.m_val<<endl;
    a2.m_val=30;
    cout<<"rf.m_val="<<rf.m_val<<"   "<<"a2.m_val= "<<a2.m_val<<endl;
    return 0;
}

rf=move(a2);不是二次引用,而是等价为a1=move(a2),因为rf就是a1,这里一个移动赋值运算符被调用了

牢牢记住,右值引用就是给右值(纯右值、将亡值)起个别名,延长右值的生命周期,没看到多大的使用价值。

另外,定义右值引用的时候,经常看到move函数,但是右值引用和move没有任何关系,move的作用是把一个左值强制转换为右值


http://www.kler.cn/a/520306.html

相关文章:

  • R语言学习笔记之高效数据操作
  • FPGA实现任意角度视频旋转(完结)视频任意角度旋转实现
  • 笔试-二维数组2
  • 基于RDMA GPUDirect技术的NCCL XCCL库体系结构效率问题疑补
  • 延迟之争:LLM服务的制胜关键
  • 【Nginx】【SSE】【WebSocket】Nginx配置SSE,WebSocket的转发请求
  • ui-automator定位官网文档下载及使用
  • 第25篇 基于ARM A9处理器用C语言实现中断<一>
  • 无人机微波图像传输数据链技术详解
  • STM32使用VScode开发
  • XML外部实体注入--漏洞利用
  • 亚博microros小车-原生ubuntu支持系列:13 激光雷达避障
  • 基于OSAL的嵌入式裸机事件驱动框架——软件定时器osal_timer
  • 自由学习记录(32)
  • [VSCode] vscode下载安装及安装中文插件详解(附下载链接)
  • HBase-2.5.10 伪分布式环境搭建【Mac】
  • linux ——waitpid介绍及示例
  • Office2021下载与安装保姆级教程【Office Tool Plus】
  • 蓝桥杯c/c++需要掌握的基础语法总结
  • AWS Wavelength
  • LeetCode:2412. 完成所有交易的初始最少钱数(贪心 java)
  • Spring MVC 中的 DispatcherServlet:工作流程与应用场景解析
  • FreeRTOS实时操作系统学习小结
  • kubernetes 核心技术-Service
  • 【SQL注入】DVWA靶场SQL注入实践
  • 在线可编辑Excel