使用C++11智能指针实现观察者模式时程序崩溃求助
问题分析与解决方案
崩溃核心原因
你代码里的崩溃根源在于Observer构造函数中错误的shared_ptr转换:
subject->attach(static_cast<ObserverSPtr>(this));
这里直接将裸指针this强转为shared_ptr<iobserver>,会生成一个全新的智能指针控制块,和make_shared<Observer>创建实例时的控制块完全独立。这会导致同一个Observer对象被两个无关联的shared_ptr管理,当对象析构时,两个控制块都会尝试释放内存,触发重复释放崩溃;同时detach时,用外部的observer3(来自make_shared)去匹配Subject中存储的错误shared_ptr,根本找不到目标,后续操作也会引发异常。
另外,你给Subject添加enable_shared_from_this是多余的——崩溃和Subject的智能指针管理无关,问题出在Observer的shared_ptr传递上。
修复后的完整代码
#include <iostream> #include <memory> #include <list> // 观察者接口 class iobserver { public: virtual void update() = 0; virtual ~iobserver() = default; // 虚析构,确保子类正确析构 }; using ObserverSPtr = std::shared_ptr<iobserver>; using ObserverWPtr = std::weak_ptr<iobserver>; // 主题接口 class isubject { public: virtual void notifyall() = 0; virtual void attach(ObserverSPtr observer) = 0; virtual void detach(ObserverSPtr observer) = 0; virtual int& getState() = 0; virtual void setState(int state) = 0; virtual ~isubject() = default; }; using SubjectSptr = std::shared_ptr<isubject>; class Subject : public isubject { int state; std::list<ObserverWPtr> subscribed_observers; // 改用弱引用存储观察者 public: Subject() : state(-1) {} void attach(ObserverSPtr observer) override { subscribed_observers.push_back(observer); } void detach(ObserverSPtr observer) override { // 遍历列表,找到对应观察者的弱引用并移除 subscribed_observers.remove_if([&](const ObserverWPtr& wptr) { auto sptr = wptr.lock(); return sptr && sptr == observer; }); } void notifyall() override { // 遍历前复制列表,避免遍历过程中列表被修改(比如detach)导致迭代器失效 auto observers_copy = subscribed_observers; for (auto& wptr : observers_copy) { auto sptr = wptr.lock(); if (sptr) // 检查观察者是否还存活 { sptr->update(); } else { // 清理已失效的弱引用(可选,也可以定期清理) subscribed_observers.remove(wptr); } } } int& getState() override { return state; } void setState(int state) override { this->state = state; this->notifyall(); } }; class Observer : public iobserver, public std::enable_shared_from_this<Observer> { std::weak_ptr<isubject> subject; public: Observer(SubjectSptr sub) : subject(sub) { // 使用shared_from_this获取正确的shared_ptr,和make_shared创建的实例关联 sub->attach(shared_from_this()); } void update() override { auto sub_ptr = subject.lock(); if (sub_ptr) // 检查主题是否存活 { std::cout << "Subject got updated to new state:" << sub_ptr->getState() << std::endl; } } }; // 驱动代码 int main() { auto subject = std::make_shared<Subject>(); auto observer1 = std::make_shared<Observer>(subject); auto observer2 = std::make_shared<Observer>(subject); auto observer3 = std::make_shared<Observer>(subject); subject->setState(2); std::cout << "移除observer3后:" << std::endl; subject->detach(observer3); subject->setState(5); return 0; }
高效实现观察者模式的要点
正确使用enable_shared_from_this
永远不要直接将裸指针转换为shared_ptr,必须通过shared_from_this()获取和实例关联的智能指针,避免控制块重复创建。用weak_ptr存储观察者
- 避免Subject延长观察者的生命周期,让观察者的生命周期由外部管理。
- 防止潜在的循环引用(比如如果Subject也被观察者持有shared_ptr时)。
- 通知前通过
lock()检查观察者是否存活,避免访问已销毁的对象。
避免遍历过程中修改容器
通知时先复制观察者列表,或者使用安全的迭代方式,防止detach操作导致迭代器失效。添加虚析构函数
接口类(iobserver、isubject)必须添加虚析构函数,确保子类对象通过基类指针被正确析构。
内容的提问来源于stack exchange,提问作者Meraj Hussain
相关产品推荐
相关产品推荐

