Dave N.
Dave N.

Reputation: 148

C++: Can std::variant hold vector, map, and other containers?

According to cppreference, variant is not allowed to allocate dynamic memory. This suggests that variant should not have dynamically-allocated containers as template, like vectors and maps. Yet, some say that it is possible to have a vector as a variant template. Could it be that the variant stores the vector pointer or reference, rather than the actual structure itself?

I would like to have a variant storing a vector and a map. I thought of 2 possibilities:

std::variant<std::vector<int>, std::map<int, int> > x; //stores within the variant itself ??
std::variant <std::uniqur_ptr<std::vector<int> >, std::unique_ptr<std::map<int, int> > > y; //stores only a pointer. The container is allocated elsewhere.

I would prefer the first option for its simplicity. Let me know what you think!

Upvotes: 6

Views: 2063

Answers (3)

Caleth
Caleth

Reputation: 62704

According to cppreference, variant is not allowed to allocate dynamic memory.

You are misunderstanding what that means. std::variant is not allowed to be implemented by dynamically allocating the contained object, but that contained object is allowed to do whatever it normally does.

It is the difference between

class incorrect_variant {
    union {
        std::vector<int> * vector;
        std::map<int, int> * map;
    } u;
    enum kind {
        is_vec,
        is_map,
    } k;
public:
    incorrect_variant(std::vector<int> value) : u(new std::vector<int>(value)), k(is_vec) {}

    // etc
}

class correct_variant {
    std::aligned_storage<std::max(sizeof(std::vector<int>), sizeof(std::map<int, int>)> storage;
    enum kind {
        is_vec,
        is_map,
    } k;
public:
    correct_variant(std::vector<int> value) : k(is_vec) 
    {
        new (storage) std::vector<int>(value);
    }

    // etc
}

Upvotes: 3

Aykhan Hagverdili
Aykhan Hagverdili

Reputation: 29975

You're getting it wrong.

The variant class itself allocates not a single byte (otherwise it would probably have an allocator template argument). Everything is locally in the class. But the "varianted" types themselves can allocate as much memory as they like. They own their own memory and none of this concerns std::variant. Isn't a bit like an array of std::strings. Sure, a C array doesn't allocate anything on its own, but the individual elements (strings) must do some allocation.

Upvotes: 0

milleniumbug
milleniumbug

Reputation: 15814

std::vector<T> is a class with a pointer that manages dynamically allocated memory.

std::variant by not "being allowed to allocate memory" wouldn't be able to store the std::vector<T> object itself in dynamic memory, but the vector can manage its own dynamic memory just as fine.

Upvotes: 0

Related Questions