C++ 如何在decorator模式实现中正确使用shared_ptr?

C++ 如何在decorator模式实现中正确使用shared_ptr?,c++,design-patterns,memory-leaks,decorator,shared-ptr,C++,Design Patterns,Memory Leaks,Decorator,Shared Ptr,我在下面的代码中遇到内存泄漏问题。我知道有一些流动。但不确定。如何在这些场景中使用共享的ptr?如果我需要添加更多的装饰,比如巧克力比萨冰淇淋,如何正确地传递指针,使其在出口处被删除 class AbstractCream { public: virtual void ShowFlavour() = 0; virtual ~AbstractCream() { cout << endl << "AbstractCream-DT

我在下面的代码中遇到内存泄漏问题。我知道有一些流动。但不确定。如何在这些场景中使用共享的ptr?如果我需要添加更多的装饰,比如巧克力比萨冰淇淋,如何正确地传递指针,使其在出口处被删除

    class AbstractCream
{
public:
    virtual void ShowFlavour() = 0;
    virtual ~AbstractCream()
    {
        cout << endl << "AbstractCream-DTOR";
    }
};

class IceCream :public AbstractCream
{
public:
    void ShowFlavour()
    {
        cout << "IceCream";
    }
    ~IceCream()
    {
        cout << endl << "IceCream Dtor";
    }
};

class DecoratorCream :public AbstractCream
{
private:
    std::shared_ptr<AbstractCream> AbCream;
public:
    DecoratorCream(std::shared_ptr<AbstractCream>abs) :AbCream(abs)
    {}
    void ShowFlavour()
    {
        AbCream->ShowFlavour();
    }
    virtual ~DecoratorCream()
    {
        cout << endl << "DecoratorCream-DTOR";

    }
};

class ChocolateCream : public DecoratorCream
{
public:
    ChocolateCream(std::shared_ptr<AbstractCream>abs) :DecoratorCream(abs)
    {}
    void ShowFlavour()
    {
        cout << "CholocateCream added..";
        DecoratorCream::ShowFlavour();
    }
    ~ChocolateCream()
    {
        cout << endl << "ChocolateCream-DTOR";
    }

};
class PistaCream : public DecoratorCream
{
public:
    PistaCream(std::shared_ptr<AbstractCream> abs) :DecoratorCream(abs)
    {}
    void ShowFlavour()
    {
        cout << "PistaCream added..";
        DecoratorCream::ShowFlavour();
    }
    ~PistaCream()
    {
        cout << endl << "PistaCream-DTOR";
    }
};

class StrawberryCream : public DecoratorCream
{
public:
    StrawberryCream(std::shared_ptr<AbstractCream> abs) :DecoratorCream(abs)
    {}
    void ShowFlavour()
    {
        cout << "StrawberryCream added..";
        DecoratorCream::ShowFlavour();
    }
    ~StrawberryCream()
    {
        cout << endl << "StrawberryCream-DTOR";
    }
};


int main()
{
    std::shared_ptr <AbstractCream> ice1( new IceCream());
    std::shared_ptr <PistaCream> pista1(new PistaCream(ice1));
    std::shared_ptr <AbstractCream> ice2(new IceCream());
    std::shared_ptr <ChocolateCream>choco1( new ChocolateCream(ice2));

    pista1->ShowFlavour();
    cout << endl;
    choco1->ShowFlavour();
    cout << endl;

    getchar();
    _CrtDumpMemoryLeaks();
    return 0;
}
类抽象
{
公众:
虚拟void showFlavor()=0;
虚拟~AbstractCream()
{

cout问题似乎不在于类中使用的
std::shared_ptr
:这在语义上似乎是正确的(尽管代码太多,无法详细查看)。相反,我认为您的
main()
是错误的:您试图在对象仍处于活动状态的时间点确定内存泄漏。我不是Windows程序,但我非常确定
\u CrtDumpMemoryLeak()
不知道
std::shared\u ptr
并简单地报告
新的
ed内存,它还不是
删除
d

有几种简单的方法可以更改
main()
,以避免出现问题:

  • 将对象的分配放入块中,并在块后报告内存泄漏:

    int main() {
        {
            std::shared_ptr <AbstractCream> ice1( new IceCream());
            // ...
        }
        _CrtDumpMemoryLeaks();
    }
    
  • 报告早期构造的对象的析构函数的内存泄漏,例如
    main()

    如果您也想在其他构造函数中按值传递参数,那么至少应该,
    std::move(…)
    参数。这样做可以避免引用计数,但仍然无法避免所有工作,因为它需要在每个级别上构造/销毁
    std::shared\u ptr
    。但是,至少可以避免同步维护引用计数


  • 因为我提到了一个性能问题:。它对您没有多大好处。在您的使用中,它只会减慢程序的速度。

    问题似乎不是在您的类中使用
    std::shared\u ptr
    :这似乎在语义上是正确的(但代码太多,无法详细查看)。相反,我认为您的
    main()
    是错误的:您试图在对象仍处于活动状态的时间点确定内存泄漏。我不是Windows程序,但我非常确定
    \u CrtDumpMemoryLeak()
    不知道
    std::shared\u ptr
    并简单地报告
    新的
    ed内存,它还不是
    删除
    d

    class AbstractCream
    {
    public:
        virtual void ShowFlavour() = 0;
        virtual ~AbstractCream()
        {
            cout << endl << "AbstractCream-DTOR";
        }
    };
    
    class IceCream :public AbstractCream
    {
    public:
        void ShowFlavour()
        {
            cout << "IceCream";
        }
        ~IceCream()
        {
            cout << endl << "IceCream Dtor";
        }
    };
    
    class DecoratorCream :public AbstractCream
    {
    private:
        std::shared_ptr<AbstractCream> AbCream;
    public:
        DecoratorCream(const std::shared_ptr<AbstractCream> &abs) :AbCream(abs)
        {}
        void ShowFlavour()
        {
            AbCream->ShowFlavour();
        }
        virtual ~DecoratorCream()
        {
            cout << endl << "DecoratorCream-DTOR";
    
        }
    };
    
    class ChocolateCream : public DecoratorCream
    {
    public:
        ChocolateCream(const std::shared_ptr<AbstractCream>& abs) :DecoratorCream(abs)
        {}
        void ShowFlavour()
        {
            cout << "CholocateCream added..";
            DecoratorCream::ShowFlavour();
        }
        ~ChocolateCream()
        {
            cout << endl << "ChocolateCream-DTOR";
        }
    
    };
    class PistaCream : public DecoratorCream
    {
    public:
        PistaCream(const std::shared_ptr<AbstractCream> &abs) :DecoratorCream(abs)
        {}
        void ShowFlavour()
        {
            cout << "PistaCream added..";
            DecoratorCream::ShowFlavour();
        }
        ~PistaCream()
        {
            cout << endl << "PistaCream-DTOR";
        }
    };
    
    class StrawberryCream : public DecoratorCream
    {
    public:
        StrawberryCream(const std::shared_ptr<AbstractCream>& abs) :DecoratorCream(abs)
        {}
        void ShowFlavour()
        {
            cout << "StrawberryCream added..";
            DecoratorCream::ShowFlavour();
        }
        ~StrawberryCream()
        {
            cout << endl << "StrawberryCream-DTOR";
        }
    };
    
    
    //-------------------dec--------------------------------------------------------------//
    struct DummyToLeakCheck
    {
    public:
        ~DummyToLeakCheck()
        {
            _CrtDumpMemoryLeaks();
        }
    };
    int main()
    {
        DummyToLeakCheck myLeakChecker;
        std::shared_ptr <AbstractCream> ice1( new IceCream());
        std::shared_ptr <PistaCream> pista1(new PistaCream(ice1));
        std::shared_ptr <AbstractCream> ice2(new IceCream());
        std::shared_ptr <ChocolateCream>choco1( new ChocolateCream(ice2));
        std::shared_ptr <StrawberryCream>straw1(new StrawberryCream(choco1));
    
        pista1->ShowFlavour();
        cout << endl;
        choco1->ShowFlavour();
        cout << endl;
        straw1->ShowFlavour();
        cout << endl;
    
        getchar();
    
        return 0;
    }
    
    有几种简单的方法可以更改
    main()
    ,以避免出现问题:

  • 将对象的分配放入块中,并在块后报告内存泄漏:

    int main() {
        {
            std::shared_ptr <AbstractCream> ice1( new IceCream());
            // ...
        }
        _CrtDumpMemoryLeaks();
    }
    
  • 报告早期构造的对象的析构函数的内存泄漏,例如
    main()

    如果您也想在其他构造函数中按值传递参数,那么至少应该,
    std::move(…)
    参数。这样做可以避免引用计数,但仍然无法避免所有工作,因为它需要在每个级别上构造/销毁
    std::shared\u ptr
    。但是,至少可以避免同步维护引用计数

  • 因为我提到了一个性能问题:。它对您没有多大好处。在您使用时,它只会减慢程序的速度。

    class AbstractCream
    
    class AbstractCream
    {
    public:
        virtual void ShowFlavour() = 0;
        virtual ~AbstractCream()
        {
            cout << endl << "AbstractCream-DTOR";
        }
    };
    
    class IceCream :public AbstractCream
    {
    public:
        void ShowFlavour()
        {
            cout << "IceCream";
        }
        ~IceCream()
        {
            cout << endl << "IceCream Dtor";
        }
    };
    
    class DecoratorCream :public AbstractCream
    {
    private:
        std::shared_ptr<AbstractCream> AbCream;
    public:
        DecoratorCream(const std::shared_ptr<AbstractCream> &abs) :AbCream(abs)
        {}
        void ShowFlavour()
        {
            AbCream->ShowFlavour();
        }
        virtual ~DecoratorCream()
        {
            cout << endl << "DecoratorCream-DTOR";
    
        }
    };
    
    class ChocolateCream : public DecoratorCream
    {
    public:
        ChocolateCream(const std::shared_ptr<AbstractCream>& abs) :DecoratorCream(abs)
        {}
        void ShowFlavour()
        {
            cout << "CholocateCream added..";
            DecoratorCream::ShowFlavour();
        }
        ~ChocolateCream()
        {
            cout << endl << "ChocolateCream-DTOR";
        }
    
    };
    class PistaCream : public DecoratorCream
    {
    public:
        PistaCream(const std::shared_ptr<AbstractCream> &abs) :DecoratorCream(abs)
        {}
        void ShowFlavour()
        {
            cout << "PistaCream added..";
            DecoratorCream::ShowFlavour();
        }
        ~PistaCream()
        {
            cout << endl << "PistaCream-DTOR";
        }
    };
    
    class StrawberryCream : public DecoratorCream
    {
    public:
        StrawberryCream(const std::shared_ptr<AbstractCream>& abs) :DecoratorCream(abs)
        {}
        void ShowFlavour()
        {
            cout << "StrawberryCream added..";
            DecoratorCream::ShowFlavour();
        }
        ~StrawberryCream()
        {
            cout << endl << "StrawberryCream-DTOR";
        }
    };
    
    
    //-------------------dec--------------------------------------------------------------//
    struct DummyToLeakCheck
    {
    public:
        ~DummyToLeakCheck()
        {
            _CrtDumpMemoryLeaks();
        }
    };
    int main()
    {
        DummyToLeakCheck myLeakChecker;
        std::shared_ptr <AbstractCream> ice1( new IceCream());
        std::shared_ptr <PistaCream> pista1(new PistaCream(ice1));
        std::shared_ptr <AbstractCream> ice2(new IceCream());
        std::shared_ptr <ChocolateCream>choco1( new ChocolateCream(ice2));
        std::shared_ptr <StrawberryCream>straw1(new StrawberryCream(choco1));
    
        pista1->ShowFlavour();
        cout << endl;
        choco1->ShowFlavour();
        cout << endl;
        straw1->ShowFlavour();
        cout << endl;
    
        getchar();
    
        return 0;
    }
    
    { 公众: 虚拟void showFlavor()=0; 虚拟~AbstractCream() { cout
    类抽象
    {
    公众:
    虚拟void showFlavor()=0;
    虚拟~AbstractCream()
    {
    
    CUT作为一个旁注,您应该使用<代码> STD::MaMuxSudio,并考虑<代码> STD::UnQuyJPPT。您能详细说明一下吗?我的理解是UnQuyQPTR是有用的,如果我们有一个数组来清除相似或删除[]。作为一个旁注,您应该使用<代码> STD::MaxySuffy,并考虑<代码> STD::UnQuyJPPT。您能详细说明一下吗?我的理解是UnQuyQPTR是有用的,如果我们有一个数组来清除相似或删除[]。非常感谢你的帮助。这解决了内存检查问题。它实际上是在清除内存,但检查点正如你所说的是错误的。第二点,std::endl。在换行后打印有什么更好的选择呢?最后但并非最不重要的是,我仍然无法将嵌套的新指针传递给外部共享指针。我需要d首先使用另一个共享指针创建一个,然后必须将其传递给另一个以获得更多的包装(如果是装饰器)。这是否已导出?/*下面的代码示例演示如何尝试三层装饰*/std::shared_ptr ice2(new IceCream());std::shared_ptr choco1(new Chocolate(ice2));std::shared_ptr straw1(新草莓奶油(巧克力);@Anand:re
    std::endl
    :只需使用
    '\n'
    。如果你按照答案进行操作,你会发现推理和备选方案的一份相当全面的报告。它们是所需的对象:我不是特别擅长面向对象编程,但我认为可以预期你会将对象装饰在周围。@Dietm安:谢谢。现在我知道了避免使用std::endl的原因。@Dietman:非常感谢你的帮助。这解决了内存检查问题。事实上,它清除了内存,但检查点正如你所说的是错误的。第二点,std::endl。在换行后打印有什么更好的替代方案吗?最后但并非最不重要的是,我仍然无法使用pass嵌套了指向外部共享指针的新指针。我需要先用另一个共享指针创建一个指针,然后将它传递给另一个指针以获得更多的包裹数(如果是Decorator)。这是否已导出?/*下面的代码示例演示如何尝试三层装饰*/std::shared_ptr ice2(new IceCream());std::shared_ptr choco1(新巧克力冰淇淋(ice2));std::shared_ptr straw1(新草莓奶油(choco1));@Anand:re
    std::endl
    :只需使用
    '\n'
    。如果你按照答案进行操作,你会发现推理和替代方案有一个相当透彻的书面说明
    DecoratorCream(std::shared_ptr<AbstractCream> abs)
        : AbCream(std::move(abs)) {
    }
    
    class AbstractCream
    {
    public:
        virtual void ShowFlavour() = 0;
        virtual ~AbstractCream()
        {
            cout << endl << "AbstractCream-DTOR";
        }
    };
    
    class IceCream :public AbstractCream
    {
    public:
        void ShowFlavour()
        {
            cout << "IceCream";
        }
        ~IceCream()
        {
            cout << endl << "IceCream Dtor";
        }
    };
    
    class DecoratorCream :public AbstractCream
    {
    private:
        std::shared_ptr<AbstractCream> AbCream;
    public:
        DecoratorCream(const std::shared_ptr<AbstractCream> &abs) :AbCream(abs)
        {}
        void ShowFlavour()
        {
            AbCream->ShowFlavour();
        }
        virtual ~DecoratorCream()
        {
            cout << endl << "DecoratorCream-DTOR";
    
        }
    };
    
    class ChocolateCream : public DecoratorCream
    {
    public:
        ChocolateCream(const std::shared_ptr<AbstractCream>& abs) :DecoratorCream(abs)
        {}
        void ShowFlavour()
        {
            cout << "CholocateCream added..";
            DecoratorCream::ShowFlavour();
        }
        ~ChocolateCream()
        {
            cout << endl << "ChocolateCream-DTOR";
        }
    
    };
    class PistaCream : public DecoratorCream
    {
    public:
        PistaCream(const std::shared_ptr<AbstractCream> &abs) :DecoratorCream(abs)
        {}
        void ShowFlavour()
        {
            cout << "PistaCream added..";
            DecoratorCream::ShowFlavour();
        }
        ~PistaCream()
        {
            cout << endl << "PistaCream-DTOR";
        }
    };
    
    class StrawberryCream : public DecoratorCream
    {
    public:
        StrawberryCream(const std::shared_ptr<AbstractCream>& abs) :DecoratorCream(abs)
        {}
        void ShowFlavour()
        {
            cout << "StrawberryCream added..";
            DecoratorCream::ShowFlavour();
        }
        ~StrawberryCream()
        {
            cout << endl << "StrawberryCream-DTOR";
        }
    };
    
    
    //-------------------dec--------------------------------------------------------------//
    struct DummyToLeakCheck
    {
    public:
        ~DummyToLeakCheck()
        {
            _CrtDumpMemoryLeaks();
        }
    };
    int main()
    {
        DummyToLeakCheck myLeakChecker;
        std::shared_ptr <AbstractCream> ice1( new IceCream());
        std::shared_ptr <PistaCream> pista1(new PistaCream(ice1));
        std::shared_ptr <AbstractCream> ice2(new IceCream());
        std::shared_ptr <ChocolateCream>choco1( new ChocolateCream(ice2));
        std::shared_ptr <StrawberryCream>straw1(new StrawberryCream(choco1));
    
        pista1->ShowFlavour();
        cout << endl;
        choco1->ShowFlavour();
        cout << endl;
        straw1->ShowFlavour();
        cout << endl;
    
        getchar();
    
        return 0;
    }