c++语法笔记与收藏夹

1.c++左值(lvalue)、右值(rvalue)和三/五法则

简单来说,左值就是在内存中有确定地址的变量,相当于一个可更改值的容器;相反,右值是一些临时变量,在内存中没有确定地址,相当于放进容器的值。赋值运算符(=)要求左操作数必须为左值,右操作数必须为右值。TRIANGLES的这篇博客解释了左右值的概念以及左右值的互相转换(左值可以直接隐式转换为右值,而右值只能转换为常量左值,如示例1);他的下一篇博客右值引用与移动语义中,介绍了右值引用,右值引用解决了右值只能转换为常量左值的问题,让右值也可以转换为非常量的左值。
示例1:

int x=1,y=2;		//x,y是左值;1,2是右值
int z=x+y;			//+运算符要求两个右值作为输入参数;左值x,y可以直接隐式转换为右值
int a[]={1,2,3};
int *ap=&a[0];		//&运算符将一个左值(a[0])取地址变成右值(a[0]的地址)
cout<<*(ap+1)<<endl;//*运算符将一个右值(ap+1)解引用变成一个左值(ap+1地址指向的int)
int &zref=z;		//左值可以直接赋给一个左值引用
int &ref=7;			//右值不可以直接赋给一个引用,因为引用类型应初始化为一个左值
const int &ref2=8;	//但是右值可以赋给常量引用,因为常量引用本身也不可改变,可以防止更改临时变量值

示例2:

int &&rref = 7 + 8;		//可以把右值直接赋给右值引用
cout << rref << endl;
rref++;					//之后可以更改这个引用
cout << rref << endl;

为了说明把右值赋给右值引用时究竟发生了什么,测试如下:

class A
{
public:
	int id;
	A() :id(0) { cout << "A constructed:this=" << this << endl; }
	A(int id_) :id(id_) { cout << "A constructed:this=" << this << ",id=" << id << endl; }
	~A() { cout << "A destructed:this=" << this << endl; }
};
int main()
{
	{
		A &&arref = A();
		cout << "address of arref=" << &arref << endl;
		cout << "arref.id=" << arref.id << endl;
		arref.id++;
		cout << "arref.id=" << arref.id << endl;
		//A a1(3);
		//A &&a1rref = a1;		//错误,无法将右值引用或绑定到左值
	}
	system("pause");
    return 0;
}

输出如下:
在这里插入图片描述
可以看到,arref与构造临时变量的地址是一样,说明这里没有复制发生,arref就是生成的临时变量。

所谓的三/五法则就是:一般编译器会给类自动加上一些默认的函数——析构函数、拷贝构造函数与赋值运算符重载函数——如果要自定义其中的一个,最好是三个都自定义(三法则);而五法则则涉及到移动语义,即如果自定义的类需要移动语义,还需要定义移动构造函数与移动赋值运算符重载函数(共五个函数),在右值引用与移动语义中介绍了。
这两篇博客就不做翻译了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值