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

C++11特性——右值引用与移动语义

右值引用与移动语义

右值引用 &&

左值(Lvalue):有名字,可取地址,生命周期可持续。

右值(Rvalue):临时对象,不可取地址,生命周期短,例如字面量、返回值等。

int a = 10;     // a 是左值

int b = a + 1;  // a + 1 是右值(临时值)

为什么要有右值引用?

只有左值引用(T&),没有右值引用(T&&)。导致一个问题:无法区分一个值是“即将销毁的临时变量”还是“正在使用的对象”。

右值引用的存在,是为了优化性能,避免不必要的拷贝

std::move 与 std::forward

std::move 并不真正进行“移动”,它只是一个类型转换工具,把一个变量强制转换为右值引用,从而允许“移动语义”生效。

std::move 的作用是告诉编译器:“我不再使用这个变量了,你可以把资源搬走。”

搭配右值引用,触发移动构造/移动赋值,避免不必要的拷贝。

示例:

#include<iostream>

#include<string>

class Myclass

{

    public:

    std::string data;

    Myclass(std::string& other):data(other)

    {

        std::cout<<"拷贝!"<<std::endl;

    };

    Myclass(std::string&& other):data(std::move(other))

    {

        std::cout<<"移动赋值!"<<std::endl;

    };

};

int main()

{

    std::string str{"Hello"};

    Myclass a(str);

    Myclass b = std::move(str);

    std::cout << std::endl;

    return 0;

}

std::forward:

std::forward 会根据模板参数 T 的类型,把参数转回它原来的值类别。

原理;本质就是一个 条件版的 static_cast

template<typename T>

T&& forward(typename remove_reference<T>::type& t) noexcept {

    return static_cast<T&&>(t);

}

如果 T int&(表示原来传的是左值),T&& 折叠成 int& 返回左值。

如果 T int(表示原来传的是右值),T&& 还是 int&& 返回右值。

特性

std::move

std::forward

作用

无条件把值变右值

条件保留原值类别

使用场景

想强制触发移动语义

模板中做完美转发

是否会改变左值

会变右值

不会

常见位置

普通函数内部

模板函数内部(配合 T&&)

注:std::move = “全部改成右值 std::forward = “保留原来的左/右值身份”

移动构造函数、移动赋值运算符

传统的拷贝构造函数和拷贝赋值运算符通过深拷贝(复制数据)实现对象复制,效率较低,尤其是涉及动态资源(如堆内存、文件句柄等)时。移动构造函数和移动赋值运算符的引入,允许“窃取”临时对象的资源,避免不必要的拷贝,提高程序性能。移动赋值 就是直接把旧房子的门钥匙交给你(直接接管资源),完全不用搬东西。

移动构造函数:

语法:ClassName(ClassName&& other) noexcept;

参数类型是右值引用(ClassName&&)。

noexcept 表示此函数不会抛异常

功能:

将 other 对象内部的资源(如指针)直接转移给新对象。

将 other 的资源指针置空或重置,避免双重释放。

示例:

class MyMC

{

    public:

    std::string data;

    MyMC(const std::string& str):data(str){};

    ~MyMC(){};

//移动构造函数

    MyMC(MyMC&& other):data(other.data){};

};

移动赋值运算符:同样接收右值引用参数

功能:先释放当前对象的资源(防止内存泄漏)、将 other 的资源指针接管、将 other 的资源指针置空。

语法:ClassName& operator=(ClassName&& other) noexcept;

MyMC& operator=(MyMC&& other) noexcept //重载移动赋值运算符

    {

        return *this;

    }

完美转发(perfect forwarding)

完美转发 是指在模板函数中,将接收到的参数 原封不动(保持它的左值/右值属性) 转发给另一个函数。如果你传进来的是左值,它会被当成左值转发;如果你传进来的是右值,它会被当成右值转发。

为什么需要完美转发?

模板参数 T 按值接收时,会把右值变成左值

转发引用:

template<typename T>

void func(T&& arg) { ... }

如果这种 T&& 出现在模板参数里,并且 T 要从函数参数类型推导出来,它不是普通右值引用,而是 转发引用

如果传进来是左值 T 推导成 T& 参数类型变成 T& && 折叠成 T&(左值引用)。

如果传进来是右值 T 推导成 T 参数类型是 T&&(右值引用)。

具体规则;

T& &  T&

T& && T&

T&& & T&

T&& && T&&

示例:

#include<iostream>

#include<string>

void process(int& x)

{

    std::cout<<"左值版本\n";

}

void process(int&& x)

{

    std::cout<<"右值版本\n";

}

template<typename T>

void wrapper(T&& arg)

{

    process(std::forward(arg));

}

int main()

{

    int a = 5;

    wrapper(a);   // 左值版本

    wrapper(10);  // 右值版本

    return 0;

}

http://www.lryc.cn/news/606360.html

相关文章:

  • 基于大模型的知识库落地实施策略
  • 硬件-音频学习DAY1——音箱材料选择:密度板为何完胜实木
  • opencv解迷宫
  • 图论:SPFA算法
  • 20250731在荣品的PRO-RK3566开发板的Android13下解决敦泰的FT8206触控芯片的只有4点触控功能
  • 经典算法之美:冒泡排序的优雅实现
  • 【计算机网络】IP地址、子网掩码、网关、DNS、IPV6是什么含义?计算机中如何设置子网掩码与网关?
  • 分类-鸢尾花分类
  • 基于SpringBoot和SpringAI框架实践
  • 数据转换能干什么?有哪些好用的数据转换方法?
  • 【React】diff 算法
  • 深度解析领域特定语言(DSL)第七章:语法分析器组合子 - 用乐高思维构建解析器
  • 借助于llm将pdf转化为md文本
  • 循环神经网络RNN原理精讲,详细举例!
  • 【智能体agent】入门之--2.2框架---autoGen
  • Cesium 快速入门(一)快速搭建项目
  • 【05】大恒相机SDK C#开发 —— Winform中采集图像并显示
  • 提示词增强工程(Prompt Enhancement Engineering)白皮书草稿
  • 【大模型理论篇】混合思考之自适应思维链
  • uv使用教程
  • FastMCP本地构建Server和Clinet交互
  • 用Python绘制SM2国密算法椭圆曲线:一场数学与视觉的盛宴
  • 时间戳 + 签名机制
  • 学习日志23 python
  • 因为想开发新项目了~~要给老Python项目整个虚拟环境
  • HTML基础复习:全面回顾核心概念
  • 谷歌V3插件热更新
  • 【0基础PS】Photoshop (PS) 理论知识
  • 【刷题】东方博宜oj 1412-快速幂(零基础,简单易懂)
  • Mysql-视图,函数,存储过程,触发器