(左)右值 万能引用 完美转发

C11特性之一

概念

什么是移动语义

  • 是一种高效管理资源的编程技术。它允许程序通过“移动”资源而不是“拷贝”资源的方式,来减少不必要的资源分配和释放,从而提高程序的性能。

是什么左值,什么是右值

  • 简单理解来说,可以获取地址的就是左值不能取地址的就是右值,并且右值不能出现在赋值符号左边
    • 右值的几种情况:
      • 返回值的临时拷贝。
      • 字面常量,表达式返值等。
      • 内置类型的右值:纯右值。
      • 自定义类型的右值:将亡值(生命周期很短,例如:没有实例化的匿名对象)。

什么是(左)右值引用

  • 左值引用:就是给左值取别名。

    • 右值引用可以传递给const左值
  • 右值引用:就是给右值取别名。

    • move()之后的左值可以传递给右值引用
  • (左)右值引用可以构成函数重载,并且会走更适合的引用版本,如果左右引用都可以使用的话。

1
2
3
4
int a = 0;
int& l = a; // 左值引用

int&& r1 = 10;// 右值引用

它们分别的价值

  • 左值引用

    1. 做参数
    2. 做返回值,可以减少拷贝。
  • 右值引用

    1. 减少拷贝构造的资源消耗,对于一个自定义类型的右值,如果需要它的值,不需要进行深拷贝,由于自定义类型的右值本身也就是即将被释放的资源,不如直接将其资源利用起来。即直接swap()获取资源。
    2. 衍生出移动构造和移动拷贝

万能引用

1
2
3
4
5
template<typename T>
void forwarding(T&& t)/*万能引用*/
{
func(t);
}

属性改变

如果上述情况是一个右值引用,但使用func()的时候,t的属性仍然会被当作左值,因为右值无法被修改,这会导致我们没法进行诸如swap()的操作

  • 既可以接受左值,又可以接受右值
    • 当实参是左值,那么他就是左值引用。(引用折叠——类似将两个&&折叠为了一个&)
    • 当实参是左值,那么他就是左值引用。

完美转发

完美转发

完美转发通常用于构建泛型工厂函数或包装函数。例如,你可能希望编写一个函数模板来调用另一个函数,而不改变参数的类型特性。

完美转发的简单运用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <utility> // std::forward

// 一个简单的函数,用于展示不同的参数传递特性
void process(int& x) {
std::cout << "Lvalue reference: " << x << std::endl;
}

void process(int&& x) {
std::cout << "Rvalue reference: " << x << std::endl;
}

// 通用的模板包装函数,用于完美转发参数
template<typename T>
void forwarder(T&& arg) {
process(std::forward<T>(arg)); // 使用 std::forward 完美转发参数
}

int main() {
int a = 10;
forwarder(a); // 传递左值,调用 void process(int&)
forwarder(20); // 传递右值,调用 void process(int&&)
forwarder(std::move(a)); // 显式转为右值,调用 void process(int&&)

return 0;
}


(左)右值 万能引用 完美转发
https://weihehe.top/2024/07/31/rvalue-reference/
作者
weihehe
发布于
2024年7月31日
许可协议