c++ - MVC std::shared_ptr 中的循环依赖

标签 c++ model-view-controller shared-ptr weak-ptr

我正在尝试为我的项目创建这个 MVC 结构。我是第一次使用 shared_ptr 和 weak_ptr,除了循环依赖之外还有很多问题。

模型是可观察的。 View 是观察者。

class Observable
{
    std::set< std::shared_ptr<Observer> > observers;
public:
    Observable( void );
    void registerObserver( std::shared_ptr<Observer>  );
    void removeObserver( std::shared_ptr<Observer> & );
    void notifyObservers( void );
    virtual ~Observable( void );
};


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

    class Model : public Observable 
{
public:
    Model(void);
    void internalStateChange();
    void funcForController();
    int getSomethingForView() const;
    ~Model(void);
};

class View :
public Observer
{
std::weak_ptr<Model> model;
std::shared_ptr<Controller> controller;
public:
View( const std::shared_ptr<Model> &, const std::shared_ptr<Controller> & );
void update() override;
~View(void);
};

class Controller
{
std::shared_ptr<Model> model;
std::shared_ptr<View> view;
public:
Controller( std::shared_ptr<Model> & );
void changeHappened() const;
~Controller(void);
};

我的输出是: enter image description here

这表明它在某处挂起,然后在大约 50 秒后终止,没有其他输出。 enter image description here

Controller 没有被破坏。 :(

我该如何解决这个问题?

最佳答案

这个问题在 boost 文档中也有详细记录,所以请看一下。 我自己写了一篇关于使用弱指针打破引用循环的非常快速的笔记作为我硕士论文的附录(找到它 here )。 请务必检查引用资料,因为两行内容无法完全涵盖该主题。

标准库为程序员提供了两个不同的类(事实上,还有其他智能指针),即shared_ptrweak_ptr。共享指针是一种智能指针,保留指向对象的指针和指向共享引用计数器的附加指针。每次 自动生成智能指针的拷贝引用计数 增加 1。当共享指针被销毁(或用于引用不同的对象)时,其对象的引用计数器(或用于 它的前一个对象)递减。从原始构造的共享指针 指针最初的引用计数为 1。当引用计数器 达到 0 时,指向的对象自动销毁。弱指针是 用于打破引用结构中的循环。他们可以 用于获取指向同一对象的共享指针并检查是否 对象已经被销毁。它们不涉及引用计数。 弱指针不打算直接取消引用(即它们不能 用于获取对引用对象的访问权限,因为这样做可能会导致 崩溃或随机行为;事实上,它们可以是悬挂指针)。

至于你的具体问题,重点是:你有一个类

class Controller
{
public:
std::shared_ptr<View> view;
};

和另一个类:

class View :
public Observer
{
public:
std::shared_ptr<Controller> controller;
};

然后你们“分配”一个给对方,即

std::shared_ptr<Controller> c(new Controller);
std::shared_ptr<View> v(new View);
c->view = v;
v->controller = c;

cv 超出范围时,析构函数不会被调用,因为 c 仍然有一个引用(v->controller) 和一个用于 v (c->view)。

解决方案,用两个词来说,就是用 weak_ptr 替换两个 shared_ptr 之一。当然,您不会只是随意查看两者之一,替换哪一个取决于您的设计,并且您很可能最终会替换它们(这完全取决于所有权语义)。但是,如果您(至少)替换其中之一,问题就解决了。

这同样适用于您设计中的所有引用周期

关于c++ - MVC std::shared_ptr 中的循环依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17288902/

相关文章:

c++ - Makefile 第一个规则目标

c++ - 模板和类型名称语法

c++ - 特定类型的 shared_ptr 上的默认删除器

c++ - 使用shared_ptr实现RCU(读取-复制-更新)?

c++ - 我将 vector 作为 double 传递给函数,但 Visual Studio 将其称为 unsigned int

c++ - 使用正则表达式在标准映射中查找

javascript - 在 ember.js 中,处理表单提交和保存记录的逻辑应该驻留在哪一层?

java - 如何在mysql中一次性执行7条select准备语句?

c# - 根据点击事件渲染局部 View

c++ - 有条件地使初始化列表中的 shared_ptr 为 null