shared_ptr 派生 class 不调用析构函数

Destructor is not called for shared_ptr derived class

我想为所有程序使用 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 的共享指针和设置它的方法。

这是基础classBaseComponent:

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->setExampleComponent(eC); 行,将调用构造函数。 编译器资源管理器中的实时代码:https://godbolt.org/z/E5ofEPGen

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

导致此问题的原因是什么?

谢谢。

What can be the cause for this issue?

当指针是指向资源的最后一个所有者时,共享指针会销毁它们拥有的资源。当局部变量 eCmain 的 return 被销毁时,还有另一个所有者 mM.eC 所以资源不会被销毁。同样,当本地mM被销毁时,它的资源仍然是eC之前拥有的资源。

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

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