C++ 左值与右值

左值左值引用右值右值引用
定义可以在等号左边,能够取地址,有具体名称对左值的引用只能在等会右边,不能取地址,没有具体名字对右值的引用
功能函数传参、函数返回值实现移动语义、实现完美转发
举例见下文

左值举例:

变量名

int a;

返回左值引用的函数调用

MyClass& Create();

前置自增/自减

++ i;
++ i = 100; // 正确

赋值运算、复合赋值运算

int a = 0;
a = 90;

(a += 9) =100;  // 复合

解引用

ClassA* pA = new ClassA;
*pA;//解引用

右值举例

右值分为纯右值、将亡值

纯右值

字面值

int a = 10;  // 10为纯右值

返回非引用类型的函数调用

class Test
{
 // ...
};

// Create()为纯右值
Test Create()
{
	Test t;
	return t;
}

后置自增/自减

int i = 0;
i ++;

i ++ = 109; // 编译报错

表达式

int a = 0;
int b = 0;
a - b;  // 算术表达式

a | b; // 逻辑表达式

a != b;  // 比较表达式
将亡值

C++11新引入的类型
与右值引用(移动语义)相关的功能

class MyClass
{
   //...
   MyClass(MyClass &&)
   {
   		std::cout<<"移动构造"<<std::endl;
   }

	MyClass& operator=(MyClass &&)
	{
		std::cout<<"移动赋值构造"<<std::endl;
	}
};

MyClass Create()
{
	MyClass t;
	return t;
}

// MyClass(MyClass &&)存在,则Create()调用移动构造,为将亡值
// MyClass(MyClass &&)不存在,则Create()调用移动赋值构造,为纯右值

将亡值用于触发移动构造或移动赋值构造,并进行资源转移,之后将调用析构函数

引用

别名
声明时必须要初始化
通过引用修改变量值

int && j = 100; // j为右值引用
  • cosnt 左值引用可以引用右值,但不能修改这个值
  • 右值引用通过std::move()可以指向左值
  • 声明出来的左右值引用都是左值

实现移动语义

对象赋值时,避免资源(堆、连接、文件)的重新分配(针对深拷贝场景)
通过触发移动构造以及移动拷贝构造

class A
{
public:
	A(const A& a)
	{
		ptr = new char;
		memcpy(ptr, a.ptr, sizeof(char));
		std::cout<<"拷贝构造"<<std::endl;
	}
	
	A(A&& a)
	{
		this->ptr =a.ptr;
		a.ptr = nullptr;
		std::cout<<"移动构造"<<std::endl;
	}
	
	char* ptr;
};

A a,b;
a = b;

A b;
A a(b);  // 调用A(const A& a)

A a(std::move(b)); // 调用A(A&& a)
stl应用
class A
{
// ...
};

std::list<A> alist;
alist.push_back(A());  // 移动构造 C++11 开始支持

完美转发

函数模板可以将自己的参数完美的转发给内部调用的其他函数
完美:不仅能转发值,还能保证转发值的属性(左值、右值)不变

void func(int & n)
{
	std::cout<<"lvalue="<<n<<std::endl;
}

void func(int &&n)
{
	std::cout<<"rvalue="<<n<<std::endl;
}

template<typename T>
void revoke(T &&t) // 万能引用 通过引用的方式接收左右属性的值
{
	func(std::forward<T>(t));
}

int &m = 100;
int &&n = 100;
revoke(static_cast<int&>(m));   // lvalue=
revoke(static_cast<int&&>(n));  // rvalue=

revoke(m);  // lvalue=
revoke(n);  // lvalue=

万能引用: T&& auto&& 具体类&&并不是

引用折叠规则:

  • 参数为左值或左值引用,T&& 将转化为int&
  • 参数为右值或右值引用,T&&将转化为int&&
revoke(static_cast<int&> n);
// int & && -> int&

revoke(static_cast<int&&> m);
// int && && -> int&& 

revoke(n);
// int && -> int&

std::forward(v):

  • T为左值引用,v将转化为T类型的左值
  • T为右值引用,v将转化为T类型的右值
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值