Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: how to initialize vector in map with non-zero size

Tags:

c++

c++11

stl

I have a map of vectors:

std::map<int, std::vector<bool>> mymap

At times, I need to insert a new element:

auto& newvec = mymap[42];
// Add stuff to newvec

As far is I understand (and assuming that 42 is not yet in the map), this will give me newvec with length 0 (constructed as std::vector<bool> {}) which I can then extend.

Is there a way to initialize the vector to some size n right away?

(I am not concerned about performance, just wondering if there is a way to do this).

like image 502
Nikratio Avatar asked Sep 17 '25 17:09

Nikratio


1 Answers

Wrapping the std::vector<bool>

You could wrap the std::vector<bool> you want to initialise in the following way:

template<size_t N>
struct myvector {
   myvector(): data(N) {}
   std::vector<bool> data;
};

Then, declare mymap as a map whose value type is of this wrapper type, myvector<N>, instead of std::vector<bool>. For example, for N equal to 100:

std::map<int, myvector<100>> mymap;

If the key 42 does not exist in the map yet, then:

auto& newvec = mymap[42];

will create an instance of type myvector<100>, which in turns, initialises an std::vector<bool> of size 100.

You could access the created std::vector<bool> object either through myvector's data data member or by performing reinterpret_cast<std::vector<bool>&>(newvec).


Using std::map::find() and std::map::emplace()

Another approach would be to use std::map::find() instead of std::map::operator[]() to first find out whether a given key already exists in the map by comparing its returned iterator against the one returned by std::map::end(). If the given key does not exist, then construct the vector using std::map::emplace().

In your example, the newvec could be initialized for this approach by means of the ternary opererator:

auto it = mymap.find(42); // search for an element with the key 42
bool is_key_in_map = it != mymap.end();
// if the element with the given key exists, then return it, otherwise
// construct it
auto& newvec = is_key_in_map? it->second: 
            mymap.emplace(42, std::vector<bool>(100, true)).first->second;

Actually, you can directly call std::map::emplace() without checking whether the given key already exists, but that will cost the useless creation of a temporary object (i.e., the std::vector<bool> object) if the key is already present in the map:

auto& newvec = mymap.emplace(42, std::vector<bool>(100, true)).first->second;

Since C++17: std::map::try_emplace()

You could use std::map::try_emplace() instead of std::map::emplace():

auto& newvec = mymap.try_emplace(42, 100, true).first->second;

This way, the temporary object, std::vector<bool>(100, true), won't be constructed if the map already contains the given key (i.e., if it already contains the key 42). This is, therefore, more efficient than using std::map::emplace(), since no temporary object will be constructed if not necessary. However, it does require C++17.

like image 176
ネロク・ゴ Avatar answered Sep 19 '25 05:09

ネロク・ゴ