Ant*_*lić 0 c++ observer-pattern c++11
我正在尝试实现Observer模式,但我不希望观察者通过维护引用列表来对我的程序安全负责ObservableSubject.
这意味着当Observer object生命结束时,我不想明确地调用ObservervableSubject::removeObserver(&object).
我想出了一个使用指针引用的想法ObservableSubject.
我的问题是:上面描述的实现和下面的尝试是否可行?在我的程序中发生了什么,我如何防止解除引用垃圾?
Apriori借口:这是一种理解C++的尝试,而不是应该具有实际用途或者优先于其他实现的东西.
我的解决方案:
// Example program
#include <iostream>
#include <string>
#include <vector>
class ObserverInterface {
public:
virtual ~ObserverInterface() {};
virtual void handleMessage() = 0;
};
class ObservableSubject
{
std::vector<std::reference_wrapper<ObserverInterface*>> listeners;
public:
void addObserver(ObserverInterface* obs)
{
if (&obs)
{
// is this a reference to the copied ptr?
// still, why doesnt my guard in notify protect me
this->listeners.push_back(obs);
}
}
void removeObserver(ObserverInterface* obs)
{
// todo
}
void notify()
{
for (ObserverInterface* listener : this->listeners)
{
if (listener)
{
listener->handleMessage();
}
}
}
};
class ConcreteObserver : public ObserverInterface {
void handleMessage()
{
std::cout << "ConcreteObserver: I'm doing work..." << std::endl;
}
};
int main()
{
ObservableSubject o;
{
ConcreteObserver c;
o.addListener(&c);
}
o.notify();
std::cin.get();
}
Run Code Online (Sandbox Code Playgroud)
Line in ObservableSubject::notify(): Listener->handleMessage()抛出以下异常:
Exception thrown: read access violation.
listener->**** was 0xD8BF48B. occurred
Run Code Online (Sandbox Code Playgroud)
您的程序有未定义的行为.
ObservableSubject o;
{
ConcreteObserver c;
o.addListener(&c); // Problem
}
Run Code Online (Sandbox Code Playgroud)
c当范围结束时被破坏.您最终将一个陈旧的指针存储在侦听器列表中o.
您可以通过c在相同的范围内定义o或使用动态分配的内存来解决问题.
ObservableSubject o;
ConcreteObserver c;
o.addListener(&c);
Run Code Online (Sandbox Code Playgroud)
要么
ObservableSubject o;
{
ConcreteObserver* c = new ConcreteObserver;
o.addListener(c);
}
Run Code Online (Sandbox Code Playgroud)
使用动态分配的内存时,附加范围无用.你也可以不使用它.
ObservableSubject o;
ConcreteObserver* c = new ConcreteObserver;
o.addListener(c);
Run Code Online (Sandbox Code Playgroud)
如果您选择使用第二种方法,请确保取消分配内存.你需要添加
delete c;
Run Code Online (Sandbox Code Playgroud)
在函数结束之前.
你说:
也许我不清楚.解决生命周期/陈旧指针问题是我的解决方案的目的.我知道如果我有适当的管理生命周期,或者如果我
detachObserver在观察者破坏上添加选项,我没有问题.我希望以某种方式能够判断ObservableSubject他的观察者列表是否已损坏,而Observer没有明确说明.
由于取消引用无效指针是导致未定义行为的原因,因此必须跟踪观察者的生命周期并确保在必要时更新观察者列表.没有它,你正在追求未定义的行为.