Efficient container for different derived classes in C++

Viewed 962

When programming games, I used to store all game Objects in a std::vector with initialized and fixed size. Recently I felt the need for some inheritance among the game object classes.

So lets assume I have like 40 classes derived from my class Enemy. If I want to store objects/instances of those classes in a vector, I only have the option of storing them as vector Enemy* right? So the only thing thats contiguously allocated are the pointers, right? So I still will have a lot of cache misses when those need to be dereferenced, right?

Is there any "best practice" way, of storing derived classes in coniguous allocated memory, so that looping through them takes the minimum amount of time?

2 Answers

What about this?

struct alignas(...) Base {};
struct Derived1 : Base {};
struct Derived2 : Base {};

int main()
{
    std::vector<Base> v(2);
    new (&v[0]) Derived1();
    new (&v[1]) Derived2();
    return 0;
}

Placement new does the trick. It works with polymorphism. The alignas is to ensure the vector contains objects of the same size. Replace the ... by a number (power of 2) such that instances of both Derived1 and Derived2 fit in the vector. If sizeof(Derived1) returns 16 and sizeof(Derived2) returns 24, you would need a alignas(32).

EDIT

As @KubaOber stated, alignas is not designed to manage allocation sizes, but only for positioning the object in memory. A better way to achieve your goal is using std::variant. Something like this:

int main()
{
    std::vector<std::variant<Derived1, Derived2>> v;
    v.emplace_back(Derived1());
    v.emplace_back(Derived2());

    for (const auto& e : v)
        std::visit(VisitPackage(), e);

    return 0;
}

where VisitPackage could be something like this:

struct VisitPackage
{
    void operator()(const Derived1&) { std::cout << "Derived 1.\n"; }
    void operator()(const Derived2&) { std::cout << "Derived 2.\n"; }
};
Related