c++ 特性: 右值引用与移动语义

c++11中引入了右值引用。

左值与右值

先区分左值与右值,这里参考c++ 右值引用中对左值和右值区分方法:
左值和右值都是针对表达式,左值是指表达式结束后依然存在的持久对象,右值是指表达式结束时就不再存在的临时对象。
一个区分左值和右值的简便方法是:看能不能对表达式进行取地址。如果能,则为左值;如果不能,则为右值。

int a, b;
int* pFlag = &a;
vector<int> vcTemp;
string("hello");
const int &m=1;

a 、b 是持久对象(可以对它取地址),为左值
a+b 返回一个临时对象,非持久对象(不可取地址),为右值
a++ 先拷贝a变量,然后对a自增,接着返回拷贝的临时变量,为右值
++a 对a自增,然后返回a本身,为左值
pFlag、*pFlag 都是持久对象,为左值
vcTemp[0] 重载[] 操作符,返回int& ,为持久对象,为左值。
100、string(“hello”) 都是临时对象,为右值
m 是常量引用,引用到一个右值,但引用本身是一个持久对象,故为左值。

一般的情况开销

在不使用右值引用时,程序在运行过程中产生和销毁临时变量会浪费资源,而右值引用,就相当于“窃取”了临时变量的存储地址为己用。语法是 &&

#include<iostream>
#include<utility>
using namespace std;

class A
{
    int i;
    public:    
    void play()
    {
        ++i;
    }
    ~A()
    {
        cout<<"I am out"<<endl;
    }
};

A fun()
{
    A a;
    a.play();
    //return move(a);
    return a;
}

int main()
{
    A b = fun();
}

每个编译器都有自己的优化,MinGW中,输出:

I am out

这只有输出一次,说明只建立了一次A对象,是最好的情况。
但是在VC14++中:

I am out
I am out

输出了两次,说明,即使有些编译器有优化,但是临时变量的开销依然是存在的。

移动构造函数和移动赋值运算

用一张图解释(来源:【C\C++学习】之十八、C++11六大函数(构造函数,移动构造函数,移动赋值操作符,复制构造函数,赋值操作符,析构函数) )
这里写图片描述

Talk is cheap. Let me show the code. : )

#include<iostream>
#include<utility>
#include<cstring>
using namespace std;

class A
{
    public:
    char* pData;
    A() {}
    //复制构造函数
    A(const A& a) 
    {
        pData = new char[strlen(a.pData)+1];
        strcpy(pData, a.pData);
    }
    //移动构造函数
    A(A&& a) 
    {
        pData = a.pData;
        a.pData = nullptr;        
    }

    ~A()
    {
        if(pData!=nullptr)
        {
            delete[] pData;
            pData = nullptr; //这是个好习惯
        }
    }
    //赋值运算
    A& operator= (const A& a)
    {
        pData = new char[strlen(a.pData)+1];
        strcpy(pData, a.pData);
        return *this;
    }
    //移动赋值运算
    A& operator= (A&& a)
    {
        pData = a.pData;
        a.pData = nullptr;
        return *this;
    }
    void play()
    {
        if(pData!=nullptr)
            cout<<pData;
        cout<<endl;
    }
};

int main()
{
    A a;
    a.pData = new char[10]
    {
        '1','2','3','4','5','6','7','8','9','\0'
    };
    A b = move(a);
    cout<<"a: ";
    a.play();
    cout<<"b: ";
    b.play();
}

输出:

a:
b: 123456789

参考:
c++ 右值引用
move 函数
【C\C++学习】之十八、C++11六大函数(构造函数,移动构造函数,移动赋值操作符,复制构造函数,赋值操作符,析构函数)
移动构造函数和移动赋值运算符 (C++)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值