移除Boost依赖:std::function/std::ref替代后的异常与比较问题求助
解决方案:移除Boost依赖后std::function相关问题修复
1. 修复std::function与静态成员函数的比较逻辑
原Boost代码中boost::function重载了==运算符,可直接与函数指针比较,但std::function没有这个重载,必须通过target()方法获取内部存储的可调用对象,且需指定准确的函数指针类型:
错误原因
你之前使用runner.target<void()>()是错误的:void()是函数类型,而非函数指针类型。静态成员函数Sentinel::stop的实际类型是void(*)()(无参无返回的函数指针),且target()返回的是指向内部存储对象的指针,需要解引用后才能与函数指针比较。
修复代码
#include <functional> bool NotificationQueue::evoke(std::function<void()> runner) { // 获取内部存储的函数指针(类型为void(*)()) const void(**func_ptr)() = runner.target<void(*)()>(); // 先判空(避免存储的不是目标类型时访问空指针),再解引用比较 if (func_ptr != nullptr && *func_ptr == &Sentinel::stop) { return false; } // 其他执行逻辑 runner(); return true; }
或者更简洁的C++17写法:
bool NotificationQueue::evoke(std::function<void()> runner) { if (auto func_ptr = runner.target<void(*)()>(); func_ptr != nullptr && *func_ptr == &Sentinel::stop) { return false; } runner(); return true; }
2. 解决stop函数异常触发问题
运行时抛出stop方法的异常,本质是比较逻辑失效:之前的错误写法导致evoke没有识别出stop哨兵函数,进而执行了runner(),触发了stop内部的异常。修复上述比较逻辑后,evoke会正确返回false,不会执行stop函数,异常自然消失。
3. 移除不必要的std::ref调用
原代码中使用std::ref(_stopFn)传递参数,这里存在两个问题:
_stopFn是std::function<void()>类型,存储的是轻量的函数指针,拷贝开销极小,完全不需要用引用传递;std::ref会将_stopFn包装为std::reference_wrapper,若队列中存储的是这个包装对象,一旦_stopFn被意外修改(尽管当前代码中没有),会导致队列任务执行异常。
修复代码
void NotificationQueue::postStop() { // 直接传递_stopFn的副本,无需std::ref postNotification(_stopFn); std::unique_lock<std::mutex> lock(_mutex); if (!_notificationEnabled) { _stopped = true; _enabledNotifier.notify_all(); } }
4. 功能冻结问题的解决
功能冻结大概率是因为之前的异常未被捕获,导致程序执行流程中断,或者队列处理逻辑因为异常而卡住。修复上述所有问题后,哨兵函数会被正确识别,不会触发异常,队列的正常处理流程得以恢复,冻结问题也会随之解决。
内容的提问来源于stack exchange,提问作者pesala
相关产品推荐
相关产品推荐

