Is a pointer to map of base classes valid?

I would like to iterate some code over a few maps that have different value types, but which are all derived from a base class, which I can guarantee is the first inherited class, and the classes are plain old data.

I could probably use templated functions, or use maps of pointers, but I would rather not.

This seems to work in the tests I perform. Is it valid code?

#include <iostream>
#include <map>

using std::map;

struct Base
{
    double a;
};

struct Derived : Base
{
};

map<int, Derived> mapOfDerived;
map<int, Base>    mapOfBase;

int main()
{
    mapOfDerived[2].a = 4;
    mapOfDerived[4].a = 5;
    mapOfBase   [1].a = 7;
    mapOfBase   [5].a = 1;
    
    for (auto& map_ptr :
        {   (map<int, Base>*) &mapOfDerived, 
            (map<int, Base>*) &mapOfBase
        })
    for (auto& [key, val] : *map_ptr)
    {
        std::cout << std::endl << key << " " << val.a;
    }

    return 0;
}

>Solution :

No, that’s undefined behavior.

You cannot cast a pointer to one class type to a pointer of another and use the result as if it was really pointing to an object of the target type, except if the classes are related by inheritance, which map<int, Derived> and map<int, Base> are not, or in a few very specific other situations, e.g. members of unions, which also don’t apply.

Don’t use C-style casts. They make the compiler do almost any type cast, regardless of whether the result is actually allowed to be used. Had you used a C++-style static_cast instead, the compiler would have correctly complained to you.

Leave a Reply