0

Say I have a base class and some derived classes:

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 {/*...*/}
};

and somewhere to manage my derived objects:

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

I can do update:

bm1.update();

finally I have to release the resources upon program exit:

bm1.clear();

The above scenario is fine, but the next is not:


The problem is when I add another base class and expand my derived classes:

NOTE: According to this answer: [Why should I avoid multiple inheritance in C++?, Point 3 and 4, my Base1 and Base2 are different concepts so the multiple inheritance should be fine here.

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 {/*...*/}
};

Also imagine there is a new Base2Manager, basically the same as Base1Manager.

Finally my question is, how to properly release the resources?

Apparently I can not do the release twice:

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

I have to choose only 1 manager and let it do the job, but these 2 managers are made separately and does not know each other, so what's the proper way to handle it?

Would smart pointer help? Should I add an API like addButNotRelase(Base2* p) so that I can manipulate p but not own p (like put p in a vector other than objs?

Community
  • 1
  • 1
Marson Mao
  • 2,935
  • 6
  • 30
  • 45
  • Does calling clear only once actually cause any troubles? – kraskevich Aug 07 '14 at 07:45
  • This looks like shared ownership, which should suit `std::shared_ptr`. Or, you could roll your own reference counting if `shared_ptr` is a bad fit. – molbdnilo Aug 07 '14 at 07:50
  • @user2040251 the trouble is these managers do not know each other, so it's kinda tricky to decide who should own the resource. – Marson Mao Aug 07 '14 at 08:07

1 Answers1

1

std::shared_ptr helps here as both managers own the (potentially same) pointer.

In your first example, with only one manager, you may have replaced std::shared_ptr by std::unique_ptr.

If an other class have to own the object to control lifetime, then you may use simple pointer in your manager.

The usage should look like:

// 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);
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • If I change to `vector>` and `vector>`, how to assign `new Derive1()` to both of them as a sharing memory? I tried `Derive1* d = new Derive1(); shared_ptr p1(d);` but failed to do `shared_ptr p2(p1)` cause they are different types. If I do `shared_ptr p2(d)` then `p1` and `p2` are not sharing. – Marson Mao Aug 07 '14 at 08:05
  • @MarsonMao: Usage example added. – Jarod42 Aug 07 '14 at 08:25
  • nice, this one's great, i have to learn more about smart pointer, thanks! ;) – Marson Mao Aug 07 '14 at 08:45