news 2026/5/19 2:55:28

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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 系统中,
工厂不是“设计模式练习”,
而是“算法可演化性的基础设施”。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 17:24:47

多门店管理系统如何选?功能、成本与服务全解析

于零售行业数字化转型的浪潮之际&#xff0c;多门店管理系统已然成了连锁品牌以及实体商家达成高效运营的关键工具&#xff0c;这类系统借助整合商品、库存、会员、财务以及员工管理等模块&#xff0c;助力管理者破除信息孤岛&#xff0c;达成对零散门店的集中化、标准化管控&a…

作者头像 李华
网站建设 2026/5/15 5:02:20

免费查文献的网站推荐:实用且可靠的文献查询平台汇总

做科研的第一道坎&#xff0c;往往不是做实验&#xff0c;也不是写论文&#xff0c;而是——找文献。 很多新手科研小白会陷入一个怪圈&#xff1a;在知网、Google Scholar 上不断换关键词&#xff0c;结果要么信息过载&#xff0c;要么完全抓不到重点。今天分享几个长期使用的…

作者头像 李华
网站建设 2026/5/14 7:51:39

计算机毕业设计springboot基于Java的网上花店系统 计算机毕业设计springboot基于Java的网上花店系统 Java技术驱动的Spring Boot网上花店平台开发

计算机毕业设计springboot基于Java的网上花店系统0k4sm &#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。 随着互联网的飞速发展&#xff0c;电子商务已经成为人们生活中不可或缺…

作者头像 李华
网站建设 2026/5/15 13:59:28

盲编问卷 VS 科学设计?宏智树 AI 让实证研究数据不再 “失真”

还在对着空白文档瞎编问卷题目&#xff1f;还在因为 “一题多问”“选项重叠” 被导师打回修改&#xff1f;还在苦恼收集的数据无法进行信效度检验&#xff1f;作为深耕论文写作科普的教育博主&#xff0c;后台每天都能收到社科、教育、经管专业同学的问卷设计求助。 其实&…

作者头像 李华