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

值传递+move 优化数据传递

文章目录

      • 完整代码示例:字体处理系统中的数据传递优化
      • 三种参数传递方式对比总结表
      • 三种方式在字体处理场景的具体表现对比
      • 最终建议(针对您的字体处理代码)
        • 场景描述
        • 输出示例
        • 关键点解析

完整代码示例:字体处理系统中的数据传递优化

三种参数传递方式对比总结表

​特性​​常量引用​const T&​值传递+move​T+ std::move​右值引用​T&&
​语法示例​void Process(const std::set<uint32_t>&)void Process(std::set<uint32_t>)void Process(std::set<uint32_t>&&)
​内存操作​无拷贝(只读)1次移动构造1次移动构造
​调用方式​接受左值/右值接受左值(自动移动)和右值仅接受右值(左值需显式std::move
​函数内参数状态​保持原状可安全移动(所有权转移)必须移动(否则编译警告)
​调用后原数据状态​保持完整被清空(所有权转移)被清空(所有权转移)
​适用场景​只读访问数据需要消费数据(转移所有权)明确要求调用方转移所有权
​性能表现​最佳(无额外操作)优(1次移动)优(1次移动)
​代码灵活性​高(兼容所有调用方式)最高(自动适配左/右值)低(限制调用方式)
​典型应用案例​查询/统计操作资源转移(如字体子集生成)移动构造函数
​是否推荐在您的场景使用​❌ 需要拷贝数据✅ 最佳选择⚠️ 可用但不够灵活

三种方式在字体处理场景的具体表现对比

​测试用例​​常量引用​​值传递+move​​右值引用​
Process(existing_set)安全但需内部拷贝自动移动(高效)编译错误(必须用std::move
Process(std::move(s))合法但无意义(仍只读)直接移动(高效)直接移动(高效)
Process({1,2,3})合法但需拷贝临时对象直接移动临时对象(最优)支持(高效)
​函数内是否需要拷贝​
​是否明确表达所有权转移​

最终建议(针对您的字体处理代码)

  1. ​首选方案​​:值传递+move

    void AddChars(std::set<uint32_t> codes) {subsetter.AddCharacters(std::move(codes));
    }
    
    • 👍 同时支持普通变量和临时对象

    • 👍 明确表达所有权转移意图

    • 👍 编译器自动优化移动操作

  2. ​备选方案​​:右值引用(当需要强制调用方显式转移所有权时)

    void AddChars(std::set<uint32_t>&& codes) {subsetter.AddCharacters(std::move(codes));
    }
    
    • ⚠️ 调用时必须写AddChars(std::move(my_set))
  3. ​避免使用​​:常量引用(在需要修改/转移数据的场景)

    void AddChars(const std::set<uint32_t>& codes) {std::set<uint32_t> copy(codes); // 不必要的拷贝!subsetter.AddCharacters(std::move(copy));
    }
    
场景描述

我们实现一个字体处理器,需要高效地将字符集传递给子集生成器,避免不必要的拷贝。

#include <iostream>
#include <set>
#include <vector>
#include <string>
#include <utility>// 模拟字体子集生成器
class FontSubsetter {std::set<uint32_t> characters_;std::string features_;
public:// 接收字符集(移动语义版本)void AddCharacters(std::set<uint32_t>&& chars) {std::cout << "移动构造字符集\n";characters_ = std::move(chars);}// 保留布局特性void PreserveLayoutFeatures(bool keep) {features_ = keep ? "kern,liga" : "";}void ShowStatus() const {std::cout << "当前字符集大小: " << characters_.size() << ", 特性: " << (features_.empty() ? "无" : features_) << "\n";}
};// 字体数据处理类
class FontProcessor {std::vector<uint8_t> font_data_;
public:// 最佳实践:值传递 + movevoid ProcessCharacters(std::set<uint32_t> char_codes) {std::cout << "\n=== 处理字符集 ===\n";FontSubsetter subsetter;// 移动字符集到子集生成器subsetter.AddCharacters(std::move(char_codes));subsetter.PreserveLayoutFeatures(true);subsetter.ShowStatus();std::cout << "原参数大小: " << char_codes.size() << "\n";}// 对比方案1:常量引用(需要内部拷贝)void ProcessByRef(const std::set<uint32_t>& char_codes) {std::cout << "\n=== 引用方式处理 ===\n";FontSubsetter subsetter;// 必须拷贝!std::set<uint32_t> temp_copy(char_codes);subsetter.AddCharacters(std::move(temp_copy));subsetter.ShowStatus();}// 对比方案2:右值引用(限制调用方式)void ProcessByRvalueRef(std::set<uint32_t>&& char_codes) {std::cout << "\n=== 右值引用处理 ===\n";FontSubsetter subsetter;subsetter.AddCharacters(std::move(char_codes));subsetter.ShowStatus();}
};int main() {FontProcessor processor;// 准备测试数据std::set<uint32_t> common_chars = {0x4E00, 0x4E8C, 0x4E09}; // "一、二、三"auto get_temp_set = []{ return std::set<uint32_t>{0x56DB, 0x4E94}; }; // "四、五"// 测试1:值传递+move(最佳方案)std::cout << "----- 测试值传递+move -----";processor.ProcessCharacters(common_chars); // 左值自动移动构造std::cout << "调用后原集合大小: " << common_chars.size() << "\n";processor.ProcessCharacters(get_temp_set()); // 直接传递右值// 测试2:常量引用方案std::cout << "\n----- 测试常量引用 -----";common_chars = {0x4E00, 0x4E8C};processor.ProcessByRef(common_chars);std::cout << "调用后原集合大小: " << common_chars.size() << "\n";// 测试3:右值引用方案std::cout << "\n----- 测试右值引用 -----";processor.ProcessByRvalueRef(std::move(common_chars)); // 必须显式move// processor.ProcessByRvalueRef(common_chars); // 错误!不能直接传左值processor.ProcessByRvalueRef(get_temp_set()); // 可以传临时对象
}
输出示例
----- 测试值传递+move -----
=== 处理字符集 ===
移动构造字符集
当前字符集大小: 3, 特性: kern,liga
原参数大小: 0
调用后原集合大小: 0=== 处理字符集 ===
移动构造字符集
当前字符集大小: 2, 特性: kern,liga
原参数大小: 0----- 测试常量引用 -----
=== 引用方式处理 ===
移动构造字符集
当前字符集大小: 2, 特性: kern,liga
调用后原集合大小: 2----- 测试右值引用 -----
=== 右值引用处理 ===
移动构造字符集
当前字符集大小: 0, 特性: kern,liga=== 右值引用处理 ===
移动构造字符集
当前字符集大小: 2, 特性: kern,liga
关键点解析
  1. ​值传递+move的优势​​:

    • 同时支持左值和右值参数
    processor.ProcessCharacters(existing_set);  // 自动移动构造
    processor.ProcessCharacters(get_temp_set()); // 直接使用临时对象
    
    • 明确表达所有权转移语义

    • 函数内参数变量名可直接表明数据状态(将被移动)

  2. ​对比方案缺陷​​:

    • ​常量引用​​:必须内部拷贝,无法利用移动语义
    void ProcessByRef(const std::set<uint32_t>& chars) {std::set<uint32_t> temp(chars); // 强制拷贝!subsetter.AddChars(std::move(temp));
    }
    
    • ​纯右值引用​​:限制调用方式
    processor.ProcessByRvalueRef(existing_set); // 编译错误!
    processor.ProcessByRvalueRef(std::move(existing_set)); // 必须显式move
    
  3. ​移动后的状态验证​​:

    std::set<uint32_t> chars = {1, 2, 3};
    processor.ProcessCharacters(chars);
    std::cout << chars.size(); // 输出0,数据已转移
    

这个示例完整展示了在您字体处理场景中最优的参数传递方式,其他两种方案作为对比,突出了值传递+move模式的灵活性和高效性。

http://www.dtcms.com/a/331110.html

相关文章:

  • torchvision中数据集的使用与DataLoader 小土堆pytorch记录
  • Autoppt-AI驱动的演示文稿生成工具
  • 深入理解 RAG:检索增强生成技术详解
  • 通过机器学习框架实现Android手写识别输入功能
  • 【开源工具】基于硬件指纹的“一机一码”软件授权系统全实现(附完整源码)
  • MapReduce系统架构,颠覆了互联网分层架构的本质?
  • xiaozhi-esp32 仓库分析文档
  • 树莓派 4B 上部署 Minecraft PaperMC 1.20.x 的一键部署脚本
  • [论文阅读] 人工智能 + 软件工程 | 代码变更转自然语言生成中的幻觉问题研究解析
  • 智能家居主控板:智慧家庭的核心大脑
  • 华为实验 链路聚合
  • 实测对比:飞算JavaAI vs 人工编码,谁在效率与质量上更胜一筹?
  • C#WPF实战出真汁03--登录功能实现
  • 本文详细讲解QJson 的用法
  • 带root权限_贝尔RG020ET-CA融合终端S905L处理器当贝纯净版刷机教程
  • Android init.rc详解2
  • 前端vue框架
  • 算法题Day1
  • Ubuntu 22.04 远程桌面设置固定密码的方法
  • 使用colmap自制3DGaussian_Splatting数据集
  • OpenCV 形态学操作
  • spring mvc HttpMessageConverter 消息转换器
  • 性能测试环境的软硬件配置
  • SpringMVC基本原理和配置
  • 进程、进程命令、进程相关编程
  • 19. 什么是 TypedArray
  • Subarray Sums II
  • EtherCAT概念介绍
  • Python入门第1课:环境搭建与第一个程序“Hello World”
  • python学习DAY41打卡