策略接口必须声明虚析构函数,否则通过基类指针删除派生类对象将导致析构不完整和资源泄漏;应使用virtual ~strategy() = default;,尤其在std::unique_ptr容器中。

策略接口必须用虚析构函数
不加 virtual ~Strategy() = default; 会导致派生类对象通过基类指针删除时析构不完整,资源泄漏。尤其在容器里存 std::unique_ptr<strategy></strategy> 时,这个问题立刻暴露。
常见错误现象:valgrind 报告内存未释放,或析构函数里的日志只打印基类部分。
- 接口类只声明纯虚函数,不定义任何数据成员
- 所有策略实现类都继承自该接口,且各自管理自己的状态(如缓存、配置)
- 如果策略需要共享上下文,传入
const Context&而非裸指针,避免生命周期纠缠
std::function + lambda 可替代简单策略类
当策略逻辑短小、无状态、或仅需一次配置,用 std::function<double double></double> 比写一堆 AddStrategy / MulStrategy 更轻量。
使用场景:数学运算、排序比较器、回调钩子等。
立即学习“C++免费学习笔记(深入)”;
- lambda 捕获变量需注意生命周期——避免捕获局部栈变量后长期持有
std::function - 性能上,
std::function有小开销(约 16–32 字节+间接调用),高频热路径慎用 - 可与
std::bind或成员函数指针混用,但推荐统一用 lambda 提高可读性
策略注册表要防重复和空指针
运行时动态加载策略(比如插件式架构),常借助 std::map<:string std::unique_ptr>></:string> 注册。但没做校验就会 crash。
常见错误现象:at() 抛 std::out_of_range,或 operator[] 构造空指针后解引用。
- 注册前先检查 key 是否已存在,重复注册应报错或跳过
- 获取策略时用
auto it = registry.find(name); if (it != registry.end()) { ... },别直接registry[name].get() - 考虑用
std::optional<:reference_wrapper>></:reference_wrapper>封装查找结果,显式表达“可能不存在”
模板策略比虚函数调用更快,但失去运行时切换能力
把策略作为模板参数传入,比如 template<typename strategyt> class Processor</typename>,编译期绑定,零开销抽象。
适用条件:策略集合固定、无需配置文件或用户输入决定行为。
- 不能用变量控制策略类型,
if (mode == "fast") { Processor<faststrategy> p; }</faststrategy>是非法的 - 每个实例生成独立代码,可能增大二进制体积(尤其是策略多、Processor 大时)
- 若需运行时策略选择,可用工厂函数返回不同模板特化对象,再用类型擦除(如
std::any或variant)兜底











