核心是用std::function封装算法、std::any实现类型擦除以支持运行时策略替换;需统一策略id(如enum)、显式声明函数签名,避免裸指针或捕获lambda导致的类型不匹配。

用 std::function + std::any 实现运行时策略替换
核心是把算法逻辑封装成可调用对象,再用类型擦除存起来。不用虚函数继承树,避免编译期绑定和对象生命周期管理麻烦。
常见错误:直接存裸函数指针或 lambda(带捕获)到 std::function 里,但忘了它只支持单一签名;比如排序需要 std::function<bool int></bool>,而哈希需要 std::function<size_t std::string></size_t> —— 它们根本不能塞进同一个变量。
- 用
std::any存不同类型的std::function,靠外部上下文决定取哪个 - 定义统一策略 ID(如枚举
enum class StrategyType { SORT, HASH };),避免字符串拼错 - 所有策略函数必须显式声明参数和返回类型,别依赖 auto 推导后存不进
std::any - 示例:
std::any strategy = std::function<int(int, int)>{[](int a, int b) { return a < b; }};
避免 std::any 取值时的类型未定义行为
std::any 不做运行时类型检查,std::any_cast 强转失败会抛 std::bad_any_cast,但很多开发者在策略调度里没包 try/catch,导致程序崩溃。
典型场景:配置文件指定策略名,代码读取后直接 cast,但配置写错了(比如写了 "quicksort" 却没注册对应函数)。
立即学习“C++免费学习笔记(深入)”;
- 每次
std::any_cast前先用std::any::type() == typeid(...)检查 - 把策略注册做成工厂模式,用
std::map<:string std::any></:string>管理,key 是策略名,value 是已类型安全封装好的std::function - 不要在热路径(如每帧调用的哈希计算)里反复 cast,缓存 cast 后的函数引用
- 错误信息如
std::bad_any_cast必须捕获并转成可读提示,比如 “策略 ‘md5_hash’ 类型不匹配,期望 size_t(string),得到 bool(int,int)”
std::unordered_map 的哈希策略怎么热替换?
标准容器的哈希和相等函数是在模板实例化时固定的,不能运行时改。想换哈希算法(比如从默认 std::hash 切到 CityHash),得重建整个 map。
这不是性能问题,而是接口限制:你没法给已存在的 std::unordered_map 换 Hash 模板参数。
- 封装一层代理类,内部持有
std::unique_ptr<:unordered_map>></:unordered_map>,切换策略时 new 一个新 map,把旧数据 rehash 迁移过去 - 迁移成本取决于数据量,10 万条 key 大概耗几毫秒,别在实时音频回调里干这事
- 如果只是想换哈希种子(如 SipHash 的密钥),可以自定义哈希器,在构造时传 seed,这样无需重建 map
- 示例哈希器:
struct CustomHash { size_t operator()(const std::string& s) const { return siphash_13(s.data(), s.size(), seed_); } uint64_t seed_ = 0xdeadbeef; };
排序策略切换时迭代器失效与稳定性陷阱
用 std::sort 替换为 std::stable_sort 看似只是加个 stable,但实际影响远不止稳定性:前者是 O(n log n) 平均,后者通常多一倍内存开销,且某些实现对小数组退化成插入排序 —— 如果你切策略后发现排序变慢了 3 倍,大概率是这个原因。
更隐蔽的问题是:你传给 std::sort 的比较函数如果捕获了局部变量,而该变量作用域已结束,运行时行为未定义。
- 所有比较函数必须是无状态的,或用
std::shared_ptr管理捕获资源的生命周期 - 切换策略前确认容器是否被其他线程访问,
std::sort不保证线程安全,别在并发修改时调用 - 如果原算法依赖
operator,而新策略用了自定义 lambda,注意两者对相等元素的判定是否一致,否则 <code>std::lower_bound等查找可能出错 - 测试时别只看结果对不对,用
std::is_sorted+ 自定义谓词双重验证
std::any 里,程序跑着跑着就崩了。










