[C++11]新特性之右值引用

C++11 引入了右值引用和移动语义,它们能够减少拷贝次数提高C++的执行效率。
说到右值之前,要先说一下左值的概念。左值就是可以放在等号左边的值,它是一个具名变量或者是对象;右值与其相反,它是一个非具名的。

//左值引用实例
int a = 10;
int& ra = a;  //左值引用就是一个左值变量的别名,ra的值发生改变时,a的值也会发生改变
ra = 100;  // a 的值现在是100

//右值引用
int&& rra = 10; // rra 为一个右值变量,比左值引用多了一个&,另外等号右边为一个右值。

//区分左值和右值的一个快速方法:是否能够将对象进行取地址操作, 若能,则为左值;若不能,则为右值。
  • 一个测试case
#include <iostream>
using namespace std;

class Copyable {
public:
    Copyable(){}
    Copyable(const Copyable &o) {
        cout << "Copied" << endl;
    }
};
Copyable ReturnRvalue() {
    return Copyable(); //返回一个临时对象
}
void AcceptVal(Copyable a) {

}
void AcceptRef(const Copyable& a) {

}

int main() {
    cout << "pass by value: " << endl;
    AcceptVal(ReturnRvalue()); // 应该调用两次拷贝构造函数
    cout << "pass by reference: " << endl;
    AcceptRef(ReturnRvalue()); //应该只调用一次拷贝构造函数
}

因为编译器做了返回值优化操作(RVO, return value optimization),两个参数实际上他们都调用了0次构造函数。
编译时用这个命令g++ test.cpp -o test -fno-elide-constructors 能够禁止RVO,可以看到结果。

  • 类的移动构造和移动赋值
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;

class MyString
{
public:
   static size_t CCtor; //统计调用拷贝构造函数的次数
   static size_t MCtor; //统计调用移动构造函数的次数
   static size_t CAsgn; //统计调用拷贝赋值函数的次数
   static size_t MAsgn; //统计调用移动赋值函数的次数

public:
   // 构造函数
  MyString(const char* cstr=0){
      if (cstr) {
         m_data = new char[strlen(cstr)+1];
         strcpy(m_data, cstr);
      }
      else {
         m_data = new char[1];
         *m_data = '\0';
      }
  }

  // 拷贝构造函数
  MyString(const MyString& str) {
      CCtor ++;
      m_data = new char[ strlen(str.m_data) + 1 ];
      strcpy(m_data, str.m_data);
  }
  // 移动构造函数
  MyString(MyString&& str) noexcept
      :m_data(str.m_data) {
      MCtor ++;
      str.m_data = nullptr; //不再指向之前的资源了
  }

  // 拷贝赋值函数 =号重载
  MyString& operator=(const MyString& str){
      CAsgn ++;
      if (this == &str) // 避免自我赋值!!
         return *this;

      delete[] m_data;
      m_data = new char[ strlen(str.m_data) + 1 ];
      strcpy(m_data, str.m_data);
      return *this;
  }

  // 移动赋值函数 =号重载
  MyString& operator=(MyString&& str) noexcept{
      MAsgn ++;
      if (this == &str) // 避免自我赋值!!
         return *this;

      delete[] m_data;
      m_data = str.m_data;
      str.m_data = nullptr; //不再指向之前的资源了
      return *this;
  }

  ~MyString() {
      delete[] m_data;
  }

  char* get_c_str() const { return m_data; }
private:
  char* m_data;
};
size_t MyString::CCtor = 0;
size_t MyString::MCtor = 0;
size_t MyString::CAsgn = 0;
size_t MyString::MAsgn = 0;
int main()
{
   vector<MyString> vecStr;
   vecStr.reserve(1000); //先分配好1000个空间
   for(int i=0;i<1000;i++){
       vecStr.push_back(MyString("hello"));
   }
   cout << "CCtor = " << MyString::CCtor << endl;
   cout << "MCtor = " << MyString::MCtor << endl;
   cout << "CAsgn = " << MyString::CAsgn << endl;
   cout << "MAsgn = " << MyString::MAsgn << endl;
}

/* 结果
CCtor = 0
MCtor = 1000
CAsgn = 0
MAsgn = 0
*/

reference url: 简书参考

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值