责任链模式核心结构是定义虚函数handle()的Handler基类,含std::unique_ptr next_成员;子类重写handle()先判条件再决定处理或转发,链由外部用move语义组装,避免shared_ptr循环引用和空指针崩溃。

责任链模式的核心结构怎么写
责任链的本质是让多个处理器按顺序尝试处理请求,任一环节能处理就终止传递。C++里最直接的实现方式是定义一个基类 Handler,带虚函数 handle() 和指向下一个处理器的 next_handler_ 成员。
关键点在于:每个子类只关心自己是否能处理,不硬编码后续逻辑;链的组装由外部控制,不是类内部固定写死。
-
handle()必须是虚函数,且默认行为是调用next_handler_->handle()(如果存在) - 子类重写
handle()时,先判断条件,满足则处理并返回;否则显式调用next_handler_->handle() - 避免在子类中直接 new 下一个 handler —— 链的构建和生命周期管理应交给使用者
如何避免内存泄漏和空指针崩溃
责任链对象通常动态创建,又常被链式持有,容易出现悬挂指针或重复释放。最稳妥的做法是统一用 std::unique_ptr 管理所有权,且只在链头持有首节点,其余靠移动语义串联。
常见错误是让每个 handler 都 std::shared_ptr 持有 next,结果形成循环引用;或者裸指针传入后忘记初始化 next_handler_,导致 nullptr->handle() 崩溃。
立即学习“C++免费学习笔记(深入)”;
- 构造链时用
std::make_unique创建各 handler,再用std::move()赋值给前一个的next_handler_ - 在
handle()中检查next_handler_是否为空,再调用 —— 不要假设一定有下家 - 不要在 handler 内部保存对自身链的
shared_ptr,尤其避免在 lambda 或回调里捕获造成循环引用
std::optional 或返回 bool 怎么选
很多教程让 handle() 返回 bool 表示“是否已处理”,但实际中更推荐返回 std::optional<resulttype></resulttype>(比如 std::optional<int></int>),尤其是当需要向上传递计算结果时。
返回 bool 只能表达“停还是走”,无法携带数据;而 std::optional 既能表示“未处理”(std::nullopt),也能带出处理结果,下游无需额外字段或全局状态。
- 若 handler 仅做副作用(如日志、鉴权拦截),返回
bool足够 - 若需传递中间值(如解析后的 token、转换后的 ID),用
std::optional<t></t>更清晰 - 避免用
void*或std::any做泛型返回 —— 类型不安全,调试困难
为什么不该用模板参数硬编码链结构
有人会把整个链写成模板参数包,例如 Chain<authhandler ratelimithandler servicehandler></authhandler>,看似类型安全,实则破坏了运行时可配置性。
真实场景中,链顺序常由配置文件、开关或运行时策略决定(比如灰度环境跳过缓存 handler),硬编码模板链会让扩展成本陡增,还可能因模板实例化爆炸拖慢编译。
- 模板链无法在运行时插入/移除某个 handler(比如临时关闭熔断)
- 每个不同组合都会生成独立类型,增加二进制体积,且无法共用统一接口
- 调试时堆栈里全是模板展开名,难以定位问题;而虚函数调用堆栈干净直观
真正需要静态链的极少数情况,可用 CRTP + tuple 实现,但日常开发优先用虚函数+指针链 —— 它简单、可测、可调试,也足够快。


















