右值引用

转移语义的定义:

右值引用是用来支持转移语义的。转移语义可以将资源从一个对象转移到另一个对象,这样能够减少不必要的临时对象的创建、拷贝以及销毁,能够大幅度提高 C++ 应用程序的性能。(注意:不是复制不是粘贴)
作用和剪切粘贴一样的,通过转移语义,临时对象的值能够转移到其他对象里。
当然要实现功能,就要定义相应的构造函数,我们先定义一个类。

 class MyString
{
private:
    char* _data;
    size_t _len;
    void _init_data( const char* s);

public:
    MyString( const MyString& str);
    MyString&operator=( const MyString& str);
    virtual ~MyString();
};

void
MyString::_init_data(const char *s)
{
    _data = new char[_len+1];
    memcpy( _data, s, _len);
    _data[_len] = '\0';
}

MyString::MyString( const MyString& str)
{
    this->_len = str._len;
    _init_data( str._data );
    std::cout << "Copy Constructor is called! source: " << str._data << std::endl;
    return *this;
}

MyString& operator=(const MyString& str)
{
    if(this != &str)
    {
        _len = str.len;
        _init_data(str._data);
    }
    std::cout << "Copy Assigment is called! source: " << str._data << std::endl;
    return *this;
}
virtual MyString::~MyString()
{
    if( this->_data)
    {
        free(_data);
    }
}

若将参数做右值引用,则:

转移构造函数:
 MyString(MyString&& str) { 
    _len = str._len; 
    _data = str._data; 
    str._len = 0; 
    str._data = NULL; 

转移操作符:

MyString& operator=(MyString&& str) 
{ 
    if (this != &str) { 
      _len = str._len; 
      _data = str._data; 
      str._len = 0; 
      str._data = NULL; 
    } 
    return *this; 
 }

可见和拷贝构造函数类似,有几点需要注意:
* 参数(右值)的符号必须是右值引用符号,即“&&”。
* 参数(右值)不可以是常量,因为我们需要修改右值。
* 参数(右值)的资源链接和标记必须修改。否则,右值的析构函数就会释放资源。转移到新对象的资源也就无效了。

标准库函数std::move:
标准库提供了函数 std::move,这个函数以非常简单的方式将左值引用转换为右值引用。
std::move使用栗子,下面是一个简单的swap函数模板:

    template <class T> swap(T& a, T& b) 
    { 
        T tmp(a);  
        a = b;       
        b = tmp;
    }    

此函数使用一次,分别要对a,b,temp都进行一次拷贝工作,但如果使用std::move就可避免三次没必要的拷贝。

template <class T> swap(T& a, T& b)
{
    T tmp(std::move(a));
    a = (std::move(b));
    b = (std::move(tmp));
}

还有精确传递:

精确传递适用于这样的场景:需要将一组参数原封不动的传递给另一个函数。原封不动指 左值/右值和 const/non-const 属性和参数值不能变。
所以一般定义函数时需要const和非const 两种类型重载,很明显这使程序变得低效,但直接使用右值引用传入参数,只需要定义一次,就能够将所有的参数类型原封不动的传递给目标函数。
例如:
原本需要重载函数:

template <typename T> void forward_value(const T& val)
{ 
  process_value(val); 
}

template <typename T> void forward_value(T& val) 
{ 
  process_value(val); 
}

使用右值引用只需一个函数:

template <typename T> void forward_value(T&& val)
{ 
  process_value(val); 
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值