观察者模式实现没有互惠引用和智能指针

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)

R S*_*ahu 5

您的程序有未定义的行为.

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)

在函数结束之前.


更新,以回应OP的评论

你说:

也许我不清楚.解决生命周期/陈旧指针问题是我的解决方案的目的.我知道如果我有适当的管理生命周期,或者如果我detachObserver在观察者破坏上添加选项,我没有问题.我希望以某种方式能够判断ObservableSubject他的观察者列表是否已损坏,而Observer没有明确说明.

由于取消引用无效指针是导致未定义行为的原因,因此必须跟踪观察者的生命周期并确保在必要时更新观察者列表.没有它,你正在追求未定义的行为.

  • 答案是不". (2认同)