右值引用&&,移动语义std::move(),完美转发std::forward

左值可以取地址、位于等号左边;而右值没法取地址,位于等号右边。无论是左值引用还是右值引用都是左值(声明出来的左右值都有地址)

引用的本质是别名,可以通过引用修改变量的值,传参时传引用可以避免拷贝,和指针类似

右值引用的标志是 &&

int a = 5;

int &&ref_a_left = a; // error 右值引用不可以指向左值

int &&ref_a_right = 5; // ok

右值引用可以通过move()指向左值,把左值强制转换成右值

int &&ref_a_right = std::move(a); // ok

std::forward

当右值引用作为函数的形参时,在函数内部转发该参数给内部其他函数时,就会变成一个左值,这时候就可以用到完美转发了

std::forawrd<T>(t);

当T为左值引用类型时,t将被转换为T类型的左值

当T不是左值引用类型时,t将被转换为T类型的右值

如果是模板参数需要指定为T&&,如果是自动类型推导需要指定为auto &&,在这两种场景下 &&被称作未定的引用类型。而不是右值引用

### C++引用完美转发 (`std::forward`) 的用法及原理 #### 一、引用的概念 引用C++11 引入的一种新特性,它允许绑定到即将消亡的对象(即)。这种设计的主要目的是为了支持移动语义,从而避免不必要的深拷贝操作。 **基本语法:** ```cpp Type&& rvalue_ref = ...; ``` - **引用的特点:** - 引用可以绑定到临时对象或显式转换为的左。 - 如果一个引用具有名称,则它会被视为左[^2]。 **示例:** ```cpp #include <iostream> #include <memory> class LargeObject { public: LargeObject() { std::cout << "Constructor called\n"; } ~LargeObject() { std::cout << "Destructor called\n"; } LargeObject(const LargeObject&) { std::cout << "Copy Constructor called\n"; } LargeObject(LargeObject&&) noexcept { std::cout << "Move Constructor called\n"; } }; std::unique_ptr<LargeObject> createLargeObject() { return std::make_unique<LargeObject>(); } int main() { auto obj = createLargeObject(); // 移动语义生效,调用 Move 构造函数 } ``` 在这个例子中,`createLargeObject()` 返回了一个引用类型的 `std::unique_ptr` 对象。由于 `std::unique_ptr` 不可复制,只有通过移动语义才能完成赋操作[^3]。 --- #### 二、`std::move` 的作用 `std::move` 是标准库提供的一组工具之一,它的主要职责是将左强制转化为,以便触发移动语义。 **工作原理:** - `std::move` 实际上是一个类型转换函数,返回的是一个引用。 - 它不会真正“移动”任何东西,而是告诉编译器当前对象可以被视为处理。 **示例:** ```cpp #include <iostream> #include <utility> #include <string> void moveExample(std::string&& str) { std::cout << "String moved: " << str << '\n'; } int main() { std::string s = "Hello"; moveExample(std::move(s)); // 显式将左转为 std::cout << "After moving: '" << s << "'\n"; // 结果可能为空字符串 } ``` 在这里,`std::move(s)` 将原本的左 `s` 转换成了,使得 `moveExample` 函数接收到了一个引用参数[^4]。 --- #### 三、完美转发的概念与实现 完美转发是指在模板编程中保持原始实参的类别不变(无论是左还是),并将其实参与目标函数完全一致地传递下去的技术。 **核心组件:** - 使用 `std::forward<T>` 来保留实参的具体类型信息。 - 配合万能引用(Universal Reference)来匹配任意类型的输入。 **实现细节:** - 当模板形参被声明为 `T&&` 形式时,在某些上下文中它可以表示左引用或者引用。 - 此时可以通过 `std::forward<T>(arg)` 动态调整实际转发的形式。 **示例:** ```cpp #include <iostream> #include <utility> template<typename T> void forwardExample(T&& arg) { static_cast<void>(std::forward<T>(arg)); using DecayType = typename std::decay<T>::type; if constexpr (std::is_lvalue_reference_v<T>) { std::cout << "Forwarded as lvalue reference.\n"; } else { std::cout << "Forwarded as rvalue reference.\n"; } } int main() { int x = 42; forwardExample(x); // 左转发 forwardExample(42); // 转发 } ``` 上述代码展示了如何利用 `std::forward` 达成不同类型间的精确映射[^4]。 --- #### 四、总结对比 | 特性 | 描述 | |-----------------|----------------------------------------------------------------------| | **引用** | 绑定至即将销毁的对象,主要用于实现高效的数据转移 | | **`std::move`** | 把左转变为,激活移动构造/赋 | | **完美转发** | 确保模板内部能够无损地向下游函数传输原始参数的实际身份 | 这些技术共同构成了现代 C++ 中高效的资源管理框架。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值