1

I have few different classes that inherit from some Base class. Base class know who inherit him.

My task is store this in some queue and restore data later.

Here is the best I can come up with:

#include <iostream>
#include <queue>

enum class type{
    some = 0,
    other
};

struct Base{
    const type Type;
    Base(type t): Type(t) {};
};

struct Some : public Base {
        int SomeData;
        Some(): Base(type::some) {};
};

struct Other : public Base {
        int OtherData;
        Other(): Base(type::other) {};
};


std::queue<Base*> baseQueue;

void Store() {
    Some *s = new Some();
    s->SomeData = 1;

    Other *o = new Other();
    o->OtherData = 2;

    baseQueue.push(s);
    baseQueue.push(o);

}

void Process() {
    while (!baseQueue.empty()) {
        Base *b = baseQueue.front();
        if (b->Type == type::some) {
            Some *ps = (Some*) b;
            std::cout << "Some data: " << ps->SomeData << '\n';
        } else {
            Other *po = (Other*) b;
            std::cout << "Other data: " << po->OtherData << '\n';
        }
        delete b;
        baseQueue.pop();
    }
}


int main() {
    Store();
    Process();

    return 0;
}

It looks ugly because:

  • I works with pointers.
  • new and delete in different sections (In real code - in different units). Someone can push to queue like Some s; baseQueue.push(&s) and I will fail at delete. Have no idea how to avoid this.
  • I have no idea why I don't have memory leak (I delete only Base* not Some* or Other*)
  • this even don't looks like c++.

So. My question is what is common practice in such cases? Maybe container that solve such things already exist, and I am just bad in googling?

Stepan Loginov
  • 1,497
  • 4
  • 17
  • 40
  • 3
    Use smart pointers https://stackoverflow.com/questions/106508/what-is-a-smart-pointer-and-when-should-i-use-one – Hongyu Wang Jul 09 '18 at 15:20
  • 3
    Regarding your 3rd point, `Base::~Base` should be `virtual` if you use `Base*` pointers to delete derived types. – François Andrieux Jul 09 '18 at 15:21
  • 3
    You can also use polymorphism and have a `get_data` function that returns the derived member data so you can just have a virtual function call instead of an enum and if statements. – NathanOliver Jul 09 '18 at 15:21
  • 1
    To avoid cases like `Some s; baseQueue.push(&s);`, you could hide your enqueue functionality under some interface: Pass in the type of object to this interface, and it'll properly add an object (using `new` only). If you prevent access to the raw queue, you can better control what gets added to it. – frslm Jul 09 '18 at 15:54
  • 1
    "Base class know who inherit him" this is bad design from the begining – Slava Jul 09 '18 at 16:05
  • Why not have a constructor for Some and Other, parameterised, so that SomeData and OtherData are intialised? So `Some(int Data): Base(type::some) : SomeData(data) {};`. You can then do `Some *s = new Some(1);` – SJHowe Jul 09 '18 at 20:49

0 Answers0