5

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!

Dave N.
  • 138
  • 1
  • 8
  • 2
    a `variant` does not allocate dynamic memory. The `std::vector` it contains does. – bolov May 20 '21 at 15:42
  • Thanks for everyone's clarification. I really misunderstood the documentation for std::variant haha. – Dave N. May 20 '21 at 16:12

3 Answers3

3

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
}
Caleth
  • 52,200
  • 2
  • 44
  • 75
0

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.

milleniumbug
  • 15,379
  • 3
  • 47
  • 71
0

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.

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93