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类型的右值

相关推荐

  1. C++

    2024-07-15 18:04:01       17 阅读
  2. C++引用引用

    2024-07-15 18:04:01       28 阅读
  3. C++八股文 003:

    2024-07-15 18:04:01       57 阅读
  4. C++:(引用)&(引用)

    2024-07-15 18:04:01       32 阅读
  5. 引用引用

    2024-07-15 18:04:01       28 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-15 18:04:01       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-15 18:04:01       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-15 18:04:01       57 阅读
  4. Python语言-面向对象

    2024-07-15 18:04:01       68 阅读

热门阅读

  1. 网络协同新纪元:Eureka引领分布式网络管理革命

    2024-07-15 18:04:01       19 阅读
  2. deepstream tracker NvDCF未实现跟踪

    2024-07-15 18:04:01       19 阅读
  3. Mybatis

    Mybatis

    2024-07-15 18:04:01      13 阅读
  4. Kafka 入门指南

    2024-07-15 18:04:01       14 阅读
  5. 【redis】redis发布/订阅模型

    2024-07-15 18:04:01       21 阅读
  6. 理解前端内存泄露

    2024-07-15 18:04:01       25 阅读
  7. Spring Boot和Spring有什么区别

    2024-07-15 18:04:01       15 阅读
  8. python2与python3中的subprocess.Popen差异

    2024-07-15 18:04:01       19 阅读
  9. 面向开发者的提示词工程第一章-简介

    2024-07-15 18:04:01       22 阅读
  10. Python网页开发的常用框架

    2024-07-15 18:04:01       20 阅读