Как справиться с управлением ресурсами с множественным наследованием?

Скажем, у меня есть базовый класс и несколько производных классов:

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();

Вышеприведенный сценарий хорош, но следующий - нет:


Проблема в том, когда я добавляю другой базовый класс и расширяю свои производные классы:

ПРИМЕЧАНИЕ. Согласно этому ответу: [ Почему я должен избегать множественного наследования в C++? , Пункт 3 и 4, мой Base1 а также Base2 это разные понятия, поэтому множественное наследование должно быть хорошо здесь.

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 менеджера сделаны отдельно и не знают друг друга, так, как правильно обращаться с этим?

Поможет ли умный указатель? Должен ли я добавить API, как addButNotRelase(Base2* p) так что я могу манипулировать p но не собственный p (как положить p в vector Кроме как objs?

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);
Другие вопросы по тегам