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. 定义 Observer
和 Subject
类
#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. 使用 Subject
和 Observer
类
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;
}
解释
-
观察者和主题:
Observer
是一个抽象类,定义了update
方法,所有具体的观察者类都需要实现该方法。Subject
是主题类,管理所有的观察者。它使用std::weak_ptr<Observer>
来存储观察者,以避免观察者对象的生命周期被Subject
锁住。
-
weak_ptr
使用:- 在
Subject
中,观察者是通过std::weak_ptr<Observer>
存储的。weak_ptr
不会增加观察者的引用计数,避免了循环引用的问题。使用时,需要调用lock()
方法来获取一个有效的shared_ptr
,如果观察者已经被销毁(引用计数为 0),lock()
会返回一个空指针。
- 在
-
观察者的生命周期管理:
- 在
main
函数中,我们创建了两个观察者对象,并注册到主题对象中。当我们通过subject->notify()
向观察者发送通知时,只有有效的观察者会接收到通知。 - 当一个观察者被从
Subject
中移除后,它将不再接收到通知。 std::weak_ptr
确保即使观察者对象在通知过程中销毁,它也不会阻止观察者对象的销毁。
- 在
-
移除观察者:
removeObserver
方法移除了特定的观察者。我们使用std::remove_if
来从观察者列表中删除对应的观察者。如果该观察者已经被销毁,lock()
将返回nullptr
,该观察者将不会再被通知。
总结
使用 std::weak_ptr
可以有效地避免观察者模式中的循环引用问题,避免因为观察者持有主题对象的 shared_ptr
而导致无法销毁的问题。在这个示例中,Subject
类管理观察者的生命周期,而每个 Observer
使用 weak_ptr
观察主题对象,从而实现了避免循环引用和内存泄漏的功能。