右值引用的由来

https://www.bilibili.com/video/BV15v411g7Ma/?spm_id_from=autoNext
对这个视频的笔记,代码部分写的比较潦草

右值引用面对的问题来自C++的两种赋值方式

1、Buffer a;
2、Buffer* p = new Buffer();

1是开辟了内存空间的普通值,2是指向普通值内存空间的指针值

Buffer a;
Buffer a1=a;
Buffer* p = new Buffer();
Buffer* p1 = p;
前一种赋值是开辟了a1和a两个内存空间,a的内容拷贝到a1中
后一种赋值是创建了一组地址p1,指向p所在的内存空间,全程只有1个

?为什么不全部用指针
!因为c++没有GC,没有垃圾回收内存极易爆炸

#include <iostream>
class buffer(){
public:
   buffer(){buf = (char *)malloc(size:100);};
   ~buffer(){if(buf != nullptr)
     {free(buf); buf = nullptr;}
char * buf = nullptr;
buffer getBuffer()
{
Buffer buf;
Return buf;
}
void setbuffer(const buffer & buf){}
void setbuffer (const buffer && buf) {}
Int main()
{
buffer buf =getbuffer();
//getbuffer()生成了一个对象
//buffer buf又生成了一个对象
//函数内对象赋值到函数外对象中,再引用(有点耗费性能了,有了两个对象)
setbuffer(&buf);
return 0;
}
};

//构造函数创建100个字节,析构函数销毁它,未销毁前这个内存空间可以使用setbuffer()操作,但是会遇到一个问题,由于const常引用来延长将亡值,原则上这个引用改不了,其次,万一有人手一抖把不应该销毁的对象放进去了呢,那么这里set之后这个对象销毁了其他地方还需要用这个的就报错了,所以引入右值引用,表示传入的是肯定会被销毁可以临时重用的对象,所以可以用来创建,移动构造函数

注1:为避免创建多余的对象,首先想到setbuffer(&buf); -> setbuffer(getbuffer());
然而就会发现编译出错
原因在于,getbuffer()执行后就会销毁,setbuffer(被销毁的对象)就会报错
解决方法在于使用常引用
让一个常引用指向一个将亡值,将亡值的生命周期会被延长到和这个常引用相同的长度
const buffer & bufref = getbuffer();
setbuffer(const bufref);
由于常引用需要使用const作为前缀,non-const会自动转为const,但const不会自动转为non-const,这也是一系列函数使用大坑的开始,你需要检查前面使用的所有函数有没有使用const
所以我们经常会看到给拷贝构造赋值重载模板等等地方的参数表使用const

注2:右值引用是c++为了极限压榨性能所产生的

#include <iostream>

class Matrix{

public:
Matrix(int _row, int _col)
{ int row =_row;
  int col = _col;
  data =new float* [row];
  for(int I =0;i<row;i++)
  { 
     data[i] = new float[col];
     for(int j =0;j<col;j++) 
     {
        data[i][j]=0;
     }
  }
}

Matrix(const Matrix & mat)
{ int row = mat.row;
  int col = mat.col;
  data = new float* [row];
  for(int i = 0; i<row;i++)
  {
      data[i] = new float[col];
      for(int j=0;j<col;j++)
      {
         data[i][j]=mat.data[i][j];
      }
   }
}

Matrix(const Matrix && mat)
{ int row = mat.row;
  int col = mat.col;
  data = mat.data;
  mat.data = nullptr;
}
//这里的&&标识说明,编译器不会额外分配内存来拷贝构造,而是直接引用原来的内存空间,但是 Matrix&& a = getMatrix();的a是类型为右值引用的左值,a并非将亡值(为了不和之前的语法冲突),可以使用res = std::move(a)来交换内存,a的内容在不构造的情况下挪到了res中(注:如果后面还有对a的操作就会报错,因为a已经空了)

Matrix operator + (const Matrix & mat)
{
    If(mat.row != row || mat.col != col) print(“error”);
        Matrix res(mat.row,mat.col);
    for(int i= 0; i<mat.row;i++)
        for(int j=0; j<mat.col;j++)
            Res.data[i][j]=data[i][j] + mat.data[i][j];
    return res;
}
~Matrix()
{ if(data != nullptr)
{ for(int i=0; i<row;i++)
{ if(data[i])
{ delete[] data[i];
 data[i] = nullptr;
}
delete data;
}

//操作符重载,执行一次构造函数来构造res,执行一次拷贝构造函数来对return res做操作(重新分配内存用作赋值),所以Matrix r = a + b + c + d 执行了三次构造函数和三次拷贝构造函数,为了避免多次构造,提升性能,c++11可以优先使用移动构造函数(右值引用)

//注意,一定要把矩阵内部的值都销毁后再销毁矩阵,否则就是清理不干净

//注意,release模型下会有编译优化,如果自己没有这样调整右值引用,重复弄了很多构造函数和拷贝构造函数,那么release会尽可能的进行优化(效果很好,但如果一开始就注意这些细节会更好)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值