Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Map Initialize object using non-default constructor

Tags:

c++

In C++ suppose I have an unordered map defined as follows:

unordered_map<int, MyClass> my_map;
auto my_class = my_map[1];

In the above code if 1 is not present as key in my_map it will initialize MyClass with default constructor and return. But is there a way to use non-default constructor of MyClass for initialization?

like image 404
250 Avatar asked Sep 12 '18 07:09

250


1 Answers

You're right that operator[] needs the value type to be default-constructible.

insert does not:

std::unordered_map<int, MyClass> my_map;
// Populate the map here

// Get element with key "1", creating a new one
// from the given value if it doesn't already exist
auto result = my_map.insert({1, <your value here>});

This gives you a pair containing an iterator to the element (whether created new, or already present), and a boolean (telling you which was the case).

So:

auto& my_class = *result.first;
const bool was_inserted = result.second;

Now you can do whatever you like with this information. Often you won't even care about result.second and can just ignore it.

For more complex value types you can play around with emplace, which is like insert but, um, better. Say you really don't want the value to be constructed if it won't be used, and you have C++17:

auto result = my_map.try_emplace(1, <your value's ctor args here here>);

If you don't care (or don't have C++17):

auto result = my_map.emplace(1, <your value>);

This is still better than insert as it can move the value into the map, rather than copying it.

Ultimately, and if you don't even want to unnecessarily produce your ctor args, you can always just do a find first, but it's nice to try to avoid that, as the insertion operation itself will be doing a find too.

like image 63
Lightness Races in Orbit Avatar answered Nov 10 '22 14:11

Lightness Races in Orbit