Bootstrap

std::weak_ptr应用于观察者模式的示例

在 C++ 中,std::weak_ptr 是一个智能指针,用来观察由 std::shared_ptr 所管理的对象,而不增加该对象的引用计数。它通常用于避免 循环引用强引用计数的增长,特别在实现观察者模式时,weak_ptr 可以帮助观察者避免不必要的对象生命周期延长。

以下是如何使用 std::weak_ptr 来实现一个简单的观察者模式的示例。

观察者模式简介

观察者模式是一种行为设计模式,其中一个对象(主题或发布者)维护一组依赖对象(观察者),并在状态变化时通知这些观察者。主题对象的生命周期通常较长,而观察者对象的生命周期通常较短,使用 weak_ptr 可以确保观察者在主题对象销毁时不会导致内存泄漏。

示例:使用 weak_ptr 实现观察者模式

下面是一个简单的例子,其中我们有一个 Subject 类(主题),它可以注册多个 Observer(观察者)。每个观察者是通过 std::weak_ptr 来持有的,避免循环引用。

1. 定义 ObserverSubject
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>

class Observer {
public:
    virtual void update(int value) = 0;
    virtual ~Observer() = default;
};

class Subject {
private:
    std::vector<std::weak_ptr<Observer>> observers;

public:
    void addObserver(const std::shared_ptr<Observer>& observer) {
        observers.push_back(observer);
    }

    void removeObserver(const std::shared_ptr<Observer>& observer) {
        observers.erase(std::remove_if(observers.begin(), observers.end(),
            [&](const std::weak_ptr<Observer>& o) { return o.lock() == observer; }), observers.end());
    }

    void notify(int value) {
        for (auto& weakObserver : observers) {
            if (auto observer = weakObserver.lock()) {  // 如果观察者仍然存在
                observer->update(value);
            }
        }
    }
};
2. 定义具体的 Observer 实现
class ConcreteObserver : public Observer {
private:
    std::string name;

public:
    ConcreteObserver(const std::string& name) : name(name) {}

    void update(int value) override {
        std::cout << "Observer " << name << " received update with value: " << value << std::endl;
    }
};
3. 使用 SubjectObserver
int main() {
    // 创建主题对象
    std::shared_ptr<Subject> subject = std::make_shared<Subject>();

    // 创建观察者对象
    std::shared_ptr<ConcreteObserver> observer1 = std::make_shared<ConcreteObserver>("Observer1");
    std::shared_ptr<ConcreteObserver> observer2 = std::make_shared<ConcreteObserver>("Observer2");

    // 注册观察者
    subject->addObserver(observer1);
    subject->addObserver(observer2);

    // 通知观察者
    subject->notify(10);  // 所有观察者都会接收到通知

    // 移除一个观察者
    subject->removeObserver(observer1);

    // 通知剩余的观察者
    subject->notify(20);  // 只有 Observer2 会接收到通知

    // observer2 会自动销毁,而 observer1 的析构函数不会被触发
    return 0;
}

解释

  1. 观察者和主题:

    • Observer 是一个抽象类,定义了 update 方法,所有具体的观察者类都需要实现该方法。
    • Subject 是主题类,管理所有的观察者。它使用 std::weak_ptr<Observer> 来存储观察者,以避免观察者对象的生命周期被 Subject 锁住。
  2. weak_ptr 使用:

    • Subject 中,观察者是通过 std::weak_ptr<Observer> 存储的。weak_ptr 不会增加观察者的引用计数,避免了循环引用的问题。使用时,需要调用 lock() 方法来获取一个有效的 shared_ptr,如果观察者已经被销毁(引用计数为 0),lock() 会返回一个空指针。
  3. 观察者的生命周期管理:

    • main 函数中,我们创建了两个观察者对象,并注册到主题对象中。当我们通过 subject->notify() 向观察者发送通知时,只有有效的观察者会接收到通知。
    • 当一个观察者被从 Subject 中移除后,它将不再接收到通知。
    • std::weak_ptr 确保即使观察者对象在通知过程中销毁,它也不会阻止观察者对象的销毁。
  4. 移除观察者:

    • removeObserver 方法移除了特定的观察者。我们使用 std::remove_if 来从观察者列表中删除对应的观察者。如果该观察者已经被销毁,lock() 将返回 nullptr,该观察者将不会再被通知。

总结

使用 std::weak_ptr 可以有效地避免观察者模式中的循环引用问题,避免因为观察者持有主题对象的 shared_ptr 而导致无法销毁的问题。在这个示例中,Subject 类管理观察者的生命周期,而每个 Observer 使用 weak_ptr 观察主题对象,从而实现了避免循环引用和内存泄漏的功能。

;