【问题标题】:How to handle resource management with multiple inheritance?如何处理具有多重继承的资源管理?
【发布时间】:2014-09-30 08:31:49
【问题描述】:

假设我有一个基类和一些派生类:

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

class Derive1 : public Base1
{
public:
    void update() override {/*...*/}
};

class Derive2 : public Base1
{
public:
    void update() override {/*...*/}
};

以及管理我的派生对象的地方:

class Base1Manager
{
public:
    void add(Base1* p)
    {
        objs.push_back(p);
    }
    void update()
    {
        std::for_each(objs.begin(), objs.end(), [](Base1* p) { p->update(); });
    }
    void clear()
    {
        std::for_each(objs.begin(), objs.end(), [](Base1* p) { delete p; });
        objs.clear();
    }
    std::vector<Base1*> objs;
};

Base1Manager bm1;
bm1.add(new Derive1());
bm1.add(new Derive2());

我可以更新:

bm1.update();

最后我必须在程序退出时释放资源:

bm1.clear();

上面的场景没问题,下一个就不行了:


问题是当我添加另一个基类并扩展我的派生类时:

注意:根据这个答案: [Why should I avoid multiple inheritance in C++?,第 3 点和第 4 点,我的 Base1Base2 是不同的概念,所以这里的多重继承应该没问题。

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

class Base2
{
public:
    virtual ~Base2() {}
    virtual void do_different_thing() = 0;
};

class Derive1 : public Base1, public Base2
{
public:
    void update() override {/*...*/}
    void do_different_thing() override {/*...*/}
};

class Derive2 : public Base1, public Base2
{
public:
    void update() override {/*...*/}
    void do_different_thing() override {/*...*/}
};

还想象有一个新的Base2Manager,与Base1Manager基本相同。

最后我的问题是,如何正确释放资源?

显然我不能两次发布:

bm1.clear();
bm2.clear();

我只需要选择1个经理,让它做这个工作,但这2个经理是分开做的,彼此不认识,那么正确的处理方法是什么?

智能指针有帮助吗?我是否应该添加像addButNotRelase(Base2* p) 这样的API,以便我可以操作p 但不拥有p(比如将p 放入vector 而不是objs

【问题讨论】:

  • 只调用 clear 一次真的会造成任何麻烦吗?
  • 这看起来像是共享所有权,应该适合std::shared_ptr。或者,如果 shared_ptr 不合适,您可以滚动自己的引用计数。
  • @user2040251 问题是这些经理彼此不认识,所以决定谁应该拥有资源有点棘手。

标签: c++ polymorphism multiple-inheritance resource-management


【解决方案1】:

std::shared_ptr 在这里有所帮助,因为两位经理都拥有(可能相同的)指针。

在您的第一个示例中,只有一个经理,您可能已将 std::shared_ptr 替换为 std::unique_ptr

如果其他类必须拥有该对象来控制生命周期,那么您可以在管理器中使用简单的指针。

用法应该是这样的:

// The container
std::vector<std::shared_ptr<Base1>> base1s;
std::vector<std::shared_ptr<Base2>> base2s;

// The objects
std::shared_ptr<Derive1> d1 = std::make_shared<Derive1>();
std::shared_ptr<Derive2> d2 = std::make_shared<Derive2>();

// Feed the containers
base1s.push_back(d1);
base1s.push_back(d2);

base2s.push_back(d1);
base2s.push_back(d2);

【讨论】:

  • 如果我改成vector&lt;shared_ptr&lt;Base1&gt;&gt;vector&lt;shared_ptr&lt;Base2&gt;&gt;,如何将new Derive1()分配给它们作为共享内存?我试过Derive1* d = new Derive1(); shared_ptr&lt;Base1&gt; p1(d); 但没能做到shared_ptr&lt;Base2&gt; p2(p1) 因为它们是不同的类型。如果我这样做了shared_ptr&lt;Base2&gt; p2(d),那么p1p2 不会共享。
  • @MarsonMao:添加了使用示例。
  • 很好,这个很棒,我必须学习更多关于智能指针的知识,谢谢! ;)
猜你喜欢
  • 2012-01-07
  • 2018-09-11
  • 1970-01-01
  • 1970-01-01
  • 2011-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-23
相关资源
最近更新 更多