【问题标题】:Destructor is not called for shared_ptr derived classshared_ptr 派生类不调用析构函数
【发布时间】:2021-08-21 23:41:10
【问题描述】:

我想为所有程序使用shared_ptr 实现Mediator 设计模式。

这里是Mediator interface

class Mediator
{
    public:
        Mediator(){ print("Mediator()"); }
        virtual void Notify(std::shared_ptr<BaseComponent> sender) const = 0;
};

这里是ExampleMediator

class ExampleMediator : public Mediator
{
    private:
        std::shared_ptr<ExampleComponent> eC;
    public:
        void Notify(std::shared_ptr<BaseComponent> sender) const override {
            print("From Example Mediator");
        }
        void setExampleComponent(std::shared_ptr<ExampleComponent> eC_){
            eC = eC_;
        }
};

ExampleMediator 有一个指向ExampleComponent 的共享指针和一个设置它的方法。

这是BaseComponent的基类:

class BaseComponent
{
    protected:
        std::shared_ptr<Mediator> m;

    public:
        BaseComponent() { print("BaseComponent()"); }
        ~BaseComponent() { print("~BaseComponent()"); }
        void setMediator(std::shared_ptr<Mediator> m_){ m = m_; }
};

BaseComponent 有一个指向ExampleMediator 的共享指针和一个设置它的方法。

这里是ExampleComponent

class ExampleComponent: public BaseComponent
{
    public:
        ExampleComponent(){ print("ExampleComponent()"); }
        ~ExampleComponent(){ print("~ExampleComponent()"); }
        void doSomethingOnDerived(){ print("ExampleComponent job");}
};

主要功能:

int main()
{

    // Create the mediator
    auto mM = std::make_shared<ExampleMediator>();
    
    // Create the component
    auto eC = std::make_shared<ExampleComponent>();
    eC->setMediator(mM);
    
    // Set the component in the mediator
    mM->setExampleComponent(eC);
}

输出是:

Mediator()
BaseComponent()
ExampleComponent()

如果我删除mM-&gt;setExampleComponent(eC); 行,构造函数就会被调用。 Compiler Explorer 中的实时代码:https://godbolt.org/z/E5ofEPGen

我的目标是将组件用作共享指针而不是原始指针,Mediator 也是如此。

此问题的原因可能是什么?

谢谢。

【问题讨论】:

  • 您创建了一个循环:ExampleMediator 和 ExampleComponent 具有相互引用的共享指针。因此,两者的引用计数均为 1,并且没有人被释放
  • 我怎样才能将同一个ExampleMediator分享给多个BaseComponents,然后将所有BaseComponents设置成ExampleMediator呢?
  • 当然有很多解决方案。如此处所写,无论如何这是不可能的,因为双方都不存储列表,对吗?所以一侧(我假设是调解员)会有一个组件列表。然后,这可以列出共享(甚至唯一)指针,而引用中介的组件可以使用常规指针-> 无循环。由于调解员“拥有”它们,他肯定会比它们的指针寿命更长 -> 释放后无用。
  • @ChrisB ,我正在尝试理解您的评论,但如果可以的话,我需要一个示例。我正在努力理解如何正确地做到这一点

标签: c++ shared-ptr mediator


【解决方案1】:

此问题的原因可能是什么?

当指针是指向资源的最后一个所有者时,共享指针会破坏其拥有的资源。当局部变量eCmain返回时被销毁,还有另一个所有者mM.eC所以资源不会被销毁。同理,当本地的mM被销毁时,其资源仍归eC之前拥有的资源所有。

当您拥有资源时,我们通常认为所有者“依赖”该资源。如果我们将对象视为节点,将依赖关系视为边,我们会得到一个有向图。此依赖关系图不应有循环,因为这通常会导致您遇到的问题。

使用共享指针,打破循环的一种方法是削弱一个节点的所有权。这可以通过使用弱指针而不是共享指针来完成。请注意,您必须小心处理弱拥有资源在其依赖者之前被销毁的情况。

【讨论】:

    猜你喜欢
    • 2022-07-01
    • 2013-03-30
    • 2015-07-18
    • 2014-01-15
    • 1970-01-01
    • 2014-05-17
    • 2020-09-29
    • 2012-11-06
    • 2011-05-03
    相关资源
    最近更新 更多