C++11右值引用

左值与右值

左值与右值是C语言中的概念,但C标准并没有给出严格的区分方式,一般认为:可以放在=左边的,或者能够取地址的称为左值,只能放在=右边的,或者不能取地址的称为右值,但是这并不是完全准确。

比如:
a,b都是左值,b既可以放在=左侧也可以放在右侧。

int a = 10;
int b = 20;
a=b;
b=a;

左值与右值很难区分,一般认为:

  1. 普通类型的变量,可以取地址,都认为是左值。
  2. const修饰的常量,不可修改,只读类型的,理论上应该按照右值对待,但因为其可以取地址,C++11认为其是左值。
  3. 如果表达式的运行结果是一个临时变量或者对象,认为是右值。
  4. 如果表达式运行结果或单个变量是一个引用则认为是左值。

c++11中的右值

C++11对右值进行了严格的区分:
C语言中的纯右值。
比如:a+b, 100

将亡值。
比如:表达式的中间结果、函数按照值的方式进行返回。

右值引用的作用

首先我们来看深拷贝和浅拷贝

class Vector{
    int num;
    int* a;
public:
    void ShallowCopy(Vector& v);
    void DeepCopy(Vector& v);
};

浅拷贝

按位拷贝对象,创建的新对象有着原始对象属性值的一份精确拷贝(但不包括指针指向的内存)。

void Vector::ShallowCopy(Vector& v){
    this.num = v.num;
    this.a = v.a;
}

深拷贝

拷贝所有的属性(包括属性指向的动态分配的内存)。换句话说,当对象和它所引用的对象一起拷贝时即发生深拷贝。

void Vector::DeepCopy(Vector& v){
    this.num = v.num;
    this.a = new int[num];
    for(int i=0;i<num;++i){a[i]=v.a[i]}
}

可以看到,深拷贝的开销往往比浅拷贝大,所以我们就倾向尽可能使用浅拷贝。

浅拷贝存在的问题

当有指向动态分配内存的属性时,会造成多个对象共用这块动态分配内存,从而可能导致冲突。

一个可行的办法是:
每次做浅拷贝后,必须保证原始对象不再访问这块内存(即转移所有权给新对象),这样就保证这块内存永远只被一个对象使用。

那有什么对象在被拷贝后可以保证不再访问这块内存呢?
很容易就想到了将亡值。

移动语义

这里的将亡值也就是上面说的右值,使用右值引用可以有效地缓解内存的压力。

在C++11提出了移动语义概念。将一个对象中资源移动到另一个对象中的方式。

而这里的移动语义必须使用右值引用来完成。

//移动构造函数
Vector::Vector(Vector&& temp){
    this.num = temp.num;
    this.a = temp.a;
    temp.a = nullptr; 
}

移动语义的作用

  1. 可以有效的缓解内存的压力
  2. 提高程序的运行效率,因为不需要开辟空间和释放空间
  3. 移动构造函数参数不能加const类型的右值引用,因为资源无法转移而导致语义失效
  4. 在C++11中,编译器会为类默认生成一个移动构造,该移动构造为浅拷贝,因此类中涉及到资源管理时,用户必须显示定义自己的移动构造
  5. 在C++11中,拷贝构造/移动构造/赋值/移动赋值函数必须同时提供,或者同时不提供,程序才能保证类同时具有拷贝和移动语义
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值