Скажем, у меня есть базовый класс и некоторые производные классы:
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
?
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);