Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should std::map be used with a value that does not have a default constructor?

Tags:

c++

I've got a value type that I want put into a map. It has a nice default copy constructor, but does not have a default constructor.

I believe that so long as I stay away from using operator[] that everything will be OK.

However I end up with pretty ugly constructs like this to actually insert an object. (I think insert just fails if there is already a value for that key).

// equivalent to m[5]=x but without default construction

std::map<int,X>::iterator it = m.find(5);
if( it != m.end() )
{
   m->second = x;
}
else
{
  m->insert( std::make_pair(5,x) );
}

Which I believe will scan the map twice, and also looks pretty ugly.

Is there a neater / more efficient way to do this?

like image 892
Michael Anderson Avatar asked Dec 01 '11 06:12

Michael Anderson


People also ask

Does std::map require default constructor?

The default constructor is not required.

What does map return if key does not exist C++?

Here map size will increase by 1 . To search a key you can use map_name. find() , which will return map_name. end() if the key doesn't exist.

What is the complexity of std::map :: insert () method?

Time complexity: k*log(n) where n is size of map, k is no. of elements inserted.

Is std::map ordered?

Yes, a std::map<K,V> is ordered based on the key, K , using std::less<K> to compare objects, by default.


2 Answers

You can simply "insert-or-overwrite" with the standard insert function:

auto p = mymap.insert(std::make_pair(key, new_value));

if (!p.second) p.first->second = new_value;  // overwrite value if key already exists

If you want to pass the elements by rerference, make the pair explicit:

insert(std::pair<K&, V&>(key, value));

If you have a typedef for the map like map_t, you can say std::pair<map_t::key_type &, map_t::mapped_type &>, or any suitable variation on this theme.


Maybe this is best wrapped up into a helper:

template <typename Map>
void insert_forcefully(Map & m,
                       typename Map::key_type const & key,
                       typename Map::mapped_type const & value)
{
  std::pair<typename Map::iterator, bool> p = m.insert(std::pair<typename Map::key_type const &, typename Map::mapped_type const &>(key, value));
  if (!p.second) { p.first->second = value; }
}
like image 193
Kerrek SB Avatar answered Sep 30 '22 15:09

Kerrek SB


You could first get the position to insert the pair with lower_bound, then check if it's already there, and if not, insert it, providing the iterator where to insert. Something along those lines.

like image 21
Xeo Avatar answered Sep 30 '22 14:09

Xeo