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

C++(C++17/20)最佳工厂写法和SLAM应用综合示例

现代 C++(C++17/20)下的最佳工厂写法


一、现代 C++ 工厂设计的基本原则

在 C++17/20 下,好的工厂写法通常满足:

  1. RAII + 明确所有权

    • 返回std::unique_ptr<T>为默认
  2. switch/ 无 RTTI

  3. 支持扩展而不修改(OCP)

  4. 构造逻辑与业务逻辑分离

  5. 尽量零运行期成本或可控成本


二、最推荐写法:注册式工厂(Registry-based Factory)

90% 工程项目的首选

1. 基本结构

classBase{public:virtual~Base()=default;virtualvoidrun()=0;};usingCreator=std::function<std::unique_ptr<Base>()>;
classFactory{public:staticFactory&instance(){staticFactory f;returnf;}voidregisterCreator(std::string key,Creator creator){creators_.emplace(std::move(key),std::move(creator));}std::unique_ptr<Base>create(conststd::string&key)const{returncreators_.at(key)();}private:std::unordered_map<std::string,Creator>creators_;};

2. 自动注册(推荐)

template<typenameT>structAutoRegister{AutoRegister(conststd::string&key){Factory::instance().registerCreator(key,[]{returnstd::make_unique<T>();});}};
classImplA:publicBase{public:voidrun()override{}};staticAutoRegister<ImplA>regA("A");

优点

  • 零侵入
  • 插件友好
  • 新增类型无需改工厂

3. 为什么这是“现代”写法?

  • 使用unique_ptr明确所有权
  • Lambda 消除样板代码
  • static局部变量保证线程安全(C++11+)
  • 完全 OCP

三、带参数的现代工厂写法(非常常见)

1. 问题

构造函数有参数:

ImplA(intw,doubles);

2. 推荐方案:参数对象(Parameter Object)

structConfig{intwidth;doublescale;};
usingCreator=std::function<std::unique_ptr<Base>(constConfig&)>;
classFactory{public:voidregisterCreator(std::string key,Creator c){creators_[key]=std::move(c);}std::unique_ptr<Base>create(conststd::string&key,constConfig&cfg)const{returncreators_.at(key)(cfg);}private:std::unordered_map<std::string,Creator>creators_;};
Factory::instance().registerCreator("A",[](constConfig&cfg){returnstd::make_unique<ImplA>(cfg.width,cfg.scale);});

工程价值

  • 构造参数可扩展
  • 工厂接口稳定
  • 不破坏 ABI

四、C++20 改进:Concept + 工厂

适合大型工程 / 库级代码

template<typenameT>conceptProduct=std::derived_from<T,Base>&&std::default_initializable<T>;
template<Product T>voidregisterType(std::string key){Factory::instance().registerCreator(std::move(key),[]{returnstd::make_unique<T>();});}

收益

  • 编译期约束
  • 错误更早暴露
  • 接口自文档化

五、高性能版本:无std::function

当工厂在热路径中被频繁调用:

1. 问题

  • std::function可能引入堆分配
  • 虚调用 + 间接跳转

2. 解决方案:函数指针 / 模板表

usingCreator=std::unique_ptr<Base>(*)();
template<typenameT>std::unique_ptr<Base>createImpl(){returnstd::make_unique<T>();}
creators_["A"]=&createImpl<ImplA>;

权衡

  • 性能更优
  • 灵活性略降
  • 适合内核模块

六、编译期工厂(零运行期开销)

当类型集合在编译期固定

template<typenameT>std::unique_ptr<Base>create(){returnstd::make_unique<T>();}

调用方:

autoobj=create<ImplA>();

适合

  • 算法内核
  • 无运行期配置
  • 性能敏感路径

七、工厂 + 插件系统(dlopen)

典型结构:

Factory (主程序) ↑ PluginA.so → register("A") PluginB.so → register("B")

插件加载时执行:

extern"C"voidregisterPlugin(){Factory::instance().registerCreator("A",[]{returnstd::make_unique<ImplA>();});}

这是现代大型 C++ 系统最常见的用法之一。


八、现代 C++ 工厂的反例(请避免)

返回裸指针

Base*create();

工厂中塞业务逻辑

createAndRunAndValidate();

构造参数散落

create(int,int,double,bool);

九、快速选型总结

场景推荐方案
配置驱动注册式工厂
插件系统自动注册
性能敏感函数指针工厂
编译期固定模板工厂
API/SDKConcept + Factory

十、总结

现代 C++ 的工厂模式,本质是:
用类型系统 + RAII + 注册机制,
将“变化”限制在最小边界内。


一个真实 SLAM 模块的完整工厂实现

示例模块:FeatureExtractor


一、模块目标与设计边界

1. 目标

  • 支持多种特征提取算法(ORB / FAST / SuperPoint)
  • 通过配置文件选择实现
  • 不修改核心逻辑即可新增算法
  • 生命周期与 SLAM 系统一致

2. 架构位置(典型 SLAM)

Frontend ├── FeatureExtractor ← 工厂创建 ├── FeatureMatcher └── Tracker

FeatureExtractor 是典型“策略可替换模块”


二、接口定义

feature_extractor.h

#pragmaonce#include<vector>#include<opencv2/core.hpp>structFeature{cv::KeyPoint keypoint;cv::Mat descriptor;};classFeatureExtractor{public:virtual~FeatureExtractor()=default;virtualstd::vector<Feature>extract(constcv::Mat&image)=0;};

设计要点

  • 纯接口
  • 无构造参数
  • 不暴露具体实现细节

三、参数对象(Config)

extractor_config.h

#pragmaonce#include<string>structExtractorConfig{std::string type;// "ORB" / "FAST" / ...intmax_features=1000;floatscale_factor=1.2f;intlevels=8;};

关键工程点

  • 构造参数集中
  • 新增参数不破坏工厂接口
  • 易于 YAML / JSON 映射

四、具体实现(变化层)

orb_extractor.h

#pragmaonce#include"feature_extractor.h"#include"extractor_config.h"classORBExtractorfinal:publicFeatureExtractor{public:explicitORBExtractor(constExtractorConfig&cfg);std::vector<Feature>extract(constcv::Mat&image)override;private:intmax_features_;floatscale_factor_;intlevels_;};

orb_extractor.cpp

#include"orb_extractor.h"ORBExtractor::ORBExtractor(constExtractorConfig&cfg):max_features_(cfg.max_features),scale_factor_(cfg.scale_factor),levels_(cfg.levels){}std::vector<Feature>ORBExtractor::extract(constcv::Mat&image){std::vector<Feature>features;// ORB extraction logic...returnfeatures;}

五、工厂定义(核心)

feature_extractor_factory.h

#pragmaonce#include<memory>#include<unordered_map>#include<functional>#include<string>#include"feature_extractor.h"#include"extractor_config.h"classFeatureExtractorFactory{public:usingCreator=std::function<std::unique_ptr<FeatureExtractor>(constExtractorConfig&)>;staticFeatureExtractorFactory&instance();voidregisterCreator(conststd::string&type,Creator creator);std::unique_ptr<FeatureExtractor>create(constExtractorConfig&cfg)const;private:FeatureExtractorFactory()=default;std::unordered_map<std::string,Creator>creators_;};

feature_extractor_factory.cpp

#include"feature_extractor_factory.h"#include<stdexcept>FeatureExtractorFactory&FeatureExtractorFactory::instance(){staticFeatureExtractorFactory factory;returnfactory;}voidFeatureExtractorFactory::registerCreator(conststd::string&type,Creator creator){creators_[type]=std::move(creator);}std::unique_ptr<FeatureExtractor>FeatureExtractorFactory::create(constExtractorConfig&cfg)const{autoit=creators_.find(cfg.type);if(it==creators_.end()){throwstd::runtime_error("Unknown FeatureExtractor type: "+cfg.type);}returnit->second(cfg);}

六、自动注册(工程关键技巧)

extractor_register.h

#pragmaonce#include"feature_extractor_factory.h"template<typenameT>structExtractorRegistrar{ExtractorRegistrar(conststd::string&type){FeatureExtractorFactory::instance().registerCreator(type,[](constExtractorConfig&cfg){returnstd::make_unique<T>(cfg);});}};

orb_register.cpp

#include"orb_extractor.h"#include"extractor_register.h"staticExtractorRegistrar<ORBExtractor>reg_orb("ORB");

重要工程特性

  • 无需修改工厂

  • 新算法只需:

    • 新类
    • .cpp注册文件

七、系统使用方式

ExtractorConfig cfg;cfg.type="ORB";cfg.max_features=1500;autoextractor=FeatureExtractorFactory::instance().create(cfg);autofeatures=extractor->extract(image);

此处 Frontend 完全不知道 ORB 的存在


八、为什么这是“真实 SLAM 工厂实现”

1. 满足真实工程需求

  • 算法频繁切换
  • 配置驱动
  • 生命周期清晰
  • 可测试、可扩展

2. 与 SLAM 实际复杂度匹配

  • 不引入 DI 框架
  • 不过度模板化
  • 不牺牲可读性

3. 易于扩展为插件系统

libslam_core.so liborb_extractor.so libsuperpoint_extractor.so

每个插件在加载时完成注册。


九、常见坑(真实踩坑总结)

1. 静态初始化顺序问题

问题: 注册对象在工厂之前初始化
方案: 使用instance()的局部静态


2. 工厂里塞逻辑

问题: 工厂决定参数
方案: 参数由 Config 决定


3. 返回裸指针

问题: 生命周期不明确
方案:std::unique_ptr


十、总结

在真实 SLAM 系统中,
工厂不是“设计模式练习”,
而是“算法可演化性的基础设施”。


http://www.jsqmd.com/news/269287/

相关文章:

  • 如何高效使用论文搜索网站获取学术资源
  • POF|清华大学张宇飞团队:采用数据驱动湍流模型的三维增升装置模拟
  • 配电不透明,管理就无从谈起,这正是很多企业大楼的现状
  • ❿⁄₁₄ ⟦ OSCP ⬖ 研记 ⟧ 密码攻击实践 ➱ 传递Net-NTLMv2哈希
  • UL 认证光伏电表如何满足北美逆变器并网要求?
  • 企业级光储充电站能量协调控制系统的设计与应用
  • 2026版Java面试题库及答案解析
  • MATLAB 神经网络从入门到实战:零基础教程
  • Java多线程编程:使用场景与实现详解
  • 疆鸿智能ETHERCAT从站转DEVICENET主站详细解读,建议点赞收藏术语
  • 读懂价格背后的语言:如何用速卖通价格历史图表,预判市场趋势与库存风险
  • 免费查文献的网站推荐:实用且可靠的文献查询平台汇总
  • 救命神器!专科生必看10个AI论文平台测评与推荐
  • 计算机毕业设计springboot宠物信息管理系统 基于Spring Boot的宠物信息综合管理系统设计与实现 Spring Boot框架下的宠物信息管理平台开发
  • 【量化基础】数据驱动决策:从零接入StockTV实时行情API
  • 2026年轨道轴承市场报告:行业现状、驱动因素与未来发展趋势深度解析
  • 贵州省考报名今天开始!详细报名流程秒懂
  • 计算机毕业设计springboot网络云盘系统的设计与实现 基于Spring Boot框架的网络云存储系统开发与实现 Spring Boot驱动的网络云盘系统设计与开发实践
  • 构筑价格护城河:如何用速卖通价格历史监控,第一时间狙击低价跟卖
  • 英文文献检索的方法与技巧:提升学术研究效率的关键步骤
  • rce知识点
  • 实验小白必看:重组蛋白表达系统怎么选?原核与真核表达系统技术差异全解析
  • select chain_id,num_waiters,in_wait_sesc,osid,blocker_osid,substr(wait_event_text,1,30) from v$wait_
  • 【工具变量】国家数据知识产权试点DID(2000-2025年)
  • Spring AI学习:基本配置聊天客户端
  • 15款甘特图软件推荐|覆盖敏捷/瀑布管理,助力高效项目排期
  • 【扫盲】什么是coze
  • 【数据集】世界各国经济政策不确定性指数数据集(1985.1-2026.1)
  • 实时知识增强大模型:基于Flink的流式向量索引与动态RAG系统
  • 数据不会说话?宏智树 AI:一键解锁论文实证分析的硬核密码