You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

观察者模式中用std::weak_ptr替代裸指针的可行性及哈希问题咨询

关于观察者模式中使用std::weak_ptr的问题解答

1. 选择std::weak_ptr是否合理?

完全合理。观察者(Observer)与主题(Subject)属于双向无所有权的关联关系:

  • 用std::shared_ptr会导致循环引用,双方引用计数永远无法归零,引发内存泄漏;
  • 裸指针无法感知对象销毁,极易出现悬垂指针问题;
  • std::weak_ptr正好适配“观察但不拥有”的场景:它不会增加对象的引用计数,还能通过lock()方法获取临时的std::shared_ptr安全访问对象(若对象已销毁,lock()会返回空shared_ptr)。

2. 将容器改为存储std::weak_ptr<Subject<T>>是否可行?

可行,但需要解决两个核心问题:

问题1:std::unordered_set的哈希与相等性问题

这正是你遇到编译错误的根源——标准库没有为std::weak_ptr提供默认的std::hash特化,也没有适配unordered_set的默认相等性判断逻辑。你需要自定义哈希函数和相等性判断仿函数:

#include <memory>
#include <unordered_set>

template <typename T>
struct WeakPtrHash {
    size_t operator()(const std::weak_ptr<T>& wp) const {
        // 基于shared_ptr的哈希实现,跨平台可靠
        if (auto sp = wp.lock()) {
            return std::hash<std::shared_ptr<T>>{}(sp);
        }
        // 处理已过期的weak_ptr:基于控制块生成哈希(避免重复插入无效项)
        return std::hash<const void*>{}(wp._Get_control_block());
        // 注:_Get_control_block是MSVC非标准接口,跨平台可改用:
        // return std::hash<bool>{}(wp.owner_before(std::weak_ptr<T>{}));
    }
};

template <typename T>
struct WeakPtrEqual {
    bool operator()(const std::weak_ptr<T>& a, const std::weak_ptr<T>& b) const {
        // 标准方式:通过owner_before判断是否指向同一控制块,效率更高
        return !a.owner_before(b) && !b.owner_before(a);
        // 也可以用lock后的shared_ptr比较:return a.lock() == b.lock();
    }
};

// 实际使用示例
template <typename T>
class Observer {
private:
    std::unordered_set<std::weak_ptr<Subject<T>>, WeakPtrHash<Subject<T>>, WeakPtrEqual<Subject<T>>> subjects_;
};

问题2:过期weak_ptr的清理

容器中会积累指向已销毁对象的无效weak_ptr,需要主动清理:

  • 每次访问容器元素时,先调用lock()检查有效性,若返回空则从容器中移除该元素;
  • 定期触发清理逻辑(比如在添加新元素时、或Observer的特定成员函数中),遍历容器删除过期项。

3. std::unordered_set存储std::weak_ptr的边界情况注意点

  • 哈希冲突:自定义哈希函数若处理不当,会增加哈希冲突概率,影响unordered_set性能,优先采用基于shared_ptr或控制块的哈希实现;
  • 重复插入:确保相等性判断仿函数能准确识别指向同一对象的weak_ptr,避免重复插入;
  • 线程安全:weak_ptr的lock()操作是线程安全的,但unordered_set本身不是,多线程操作容器时必须加锁同步;
  • 内存开销:每个weak_ptr都会关联对象的控制块,相比裸指针有一定内存开销,但在现代C++中属于可接受的成本。

内容的提问来源于stack exchange,提问作者xyf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 04:21:49