当前位置: 首页 > article >正文

左值引用右值引用

目录

1. 什么是左值、右值

2. 什么是左值引用、右值引用

3. std::move() 移动语义

4. std::forward() 完美转发


1. 什么是左值、右值

左值可以取地址,例如位于等号左边 int a = 6 中的 a

        例如变量,左值在表达式结束后依然存在

右值不能取地址,例如位于等号右边 int a = 6 中的 6

        例如字面量或临时变量,通常表示一个即将被销毁的值

2. 什么是左值引用、右值引用

左值引用能指向左值,不能指向右值

例如 int &ref_a = a,而不能是 int &ref_a = 6;

因为右值没有地址,没办法被修改,而引用是变量的别名,实质上是一个变量,变量是有地址的

一个有地址,一个没地址,所以左值引用无法指向右值

但是,用const修饰后的左值引用是可以指向右值的,因为const左值引用不会修改指向值,

如 const int &ref_a = 6

这也是为什么要使用 const & 作为函数传参的原因之一

push_back(5);
void push_back(int &ref) {} // 报错
void push_back(const int &ref) {} // 不报错

右值引用的标志是 &&,两个取地址运算符,可以指向右值,不能指向左值

通过 std::move() 可以将左值转化为右值

int a = 5; // a 左值;5 右值
int &ref_l_a = a; // 左值引用
int &&ref_r_a = std::move(a); // move() 把左值转变成右值
ref_r_a = 6;

不管是左值引用还是右值引用,实质上还是引用,都可以通过取地址运算符拿到引用变量的地址

std::cout << "ref_l_a: " << &ref_l_a << std::endl; // ref_l_a: 0x7fffffffd9b4
std::cout << "ref_r_a: " << &ref_r_a << std::endl; // ref_r_a: 0x7fffffffd9b4

3. std::move() 移动语义

使用move()函数,将左值转化为右值

会触发移动构造函数,如果没有实现移动构造函数,会调用拷贝构造函数

#include <iostream>

class MyClass {
public:
  // 默认构造函数
  MyClass() {
    std::cout << "Default 默认构造" << std::endl;
  }

  // 拷贝构造函数
  MyClass(const MyClass &myClass) {
    std::cout << "Copy 拷贝构造" << std::endl;
  }

  // 移动构造函数
  // 如果此处不实现移动构造函数,使用move()函数的时候,会调用上面的拷贝构造函数
  MyClass(MyClass &&myClass) {
    std::cout << "Move 移动构造" << std::endl;
  }
};

int main() {
  MyClass myClass;
  MyClass myClass1 = myClass; // 调用拷贝构造函数
  MyClass myClass2 = std::move(myClass); // 调用移动构造函数

  return 0;
}

4. std::forward() 完美转发

完美转发(Perfect Forwarding)是 C++ 中一个重要的概念

主要用于模板编程,特别是在处理函数参数时

它的核心目的是在不改变参数的值类别(左值或右值)的情况下,将参数转发给另一个函数

即传入左值就是左值,传入右值就是右值

这在性能和效率上非常重要,因为它避免了不必要的拷贝和移动操作。

函数传参 void func(T&& arg) 中 T&& arg 的理解

T&& arg 是一个万能引用,也被称为转发引用

当函数模板的参数类型是 T&& 时,T 会根据传入参数的值类别来推导:

        如果传入的是左值,则 T 会推导为左值引用类型;

        如果传入的是右值,则 T 会推导为普通类型;

        由于 T 的推导机制,T&& arg 可以绑定到任意类型的值,无论是左值还是右值。

万能引用,或者说模板类型推导,是使用 std::forward() 的前提

#include <iostream>
#include <utility> // for std::forward

void process(int &x) { std::cout << "左值引用: " << x << std::endl; }

void process(int &&x) { std::cout << "右值引用: " << x << std::endl; }

template <typename T> void forwardToProcess(T &&arg) {
  // 完美转发 可以保留传入的参数类别
  process(std::forward<T>(arg)); 
  // 如果不使用 forward() 则不管传入的是左值还是右值,在函数内部,所有参数都是以左值的形式存在
  // process(arg);
}

int main() {
  int a = 10;
  forwardToProcess(a);  // 传入左值
  forwardToProcess(20); // 传入右值

  return 0;
}

http://www.kler.cn/a/349322.html

相关文章:

  • 从0开始深度学习(10)——softmax的简洁实现
  • 深入解析CSS中的!important规则
  • TypeScript 泛型程序设计指南
  • XGBoost回归预测 | MATLAB实现XGBoost极限梯度提升树多输入单输出
  • 港大和字节提出长视频生成模型Loong,可生成具有一致外观、大运动动态和自然场景过渡的分钟级长视频。
  • Node.js管理工具NVM
  • 新零售模式如何促进O2O商城系统的发展
  • [供应链] 库存盘点
  • JavaScript中的面向对象编程(OOP) - 终极指南
  • c语言 判断是否为回文数字
  • vue3之defineComponent
  • spring02 IOC DI
  • windows下载配置CAS单点登录
  • 20241008软考架构-------软考211-216答案解析
  • SVG图库工具
  • 51单片机的家庭防盗报警系统【proteus仿真+程序+报告+原理图+演示视频】
  • 微信商户号该怎么申请
  • 【Java】多线程理论
  • Granafa配置基于elasticsearch数据源的折线图
  • 反其道而行之:学会利用市场情绪反转交易