简体   繁体   中英

std::unordered_map::insert vs std::unordered_map::operator[]

I have a container of type unordered_map and I was wanting confirmation of which version I should use if I want to add an element to the map. I want it to overwrite the old value with the new presented if it exists and just add it if it does not.

I see that insert adds the element if it exits and also returns a pair of iterator and bool where the bool indicates if the insert is successful. I also see that operator[] adds the element if it does not exist and overwrites it if it does.

My question is basically if I should I be using operator[] for this purpose or are there any gotchas that I haven't considered. Also if my perception of these methods is wrong, please correct me.

here is what I was going to do. Data is a scoped enum of storage type int

void insertData(const Data _Data, const int _value)
{
 int SC_val = static_cast<int>(_Data);
 //sc val is now the integer value of the Data being added

 //returns a pair of iterator and bool indicating whether the insert was successful
auto ret = baseData.insert(std::pair<int,int>(SC_val,_value));

 if (ret.second == false)
 {//if the insert was not successful(key already exists)
     baseData[ret.first->first] = _value;
 }
}

or should I just do

int index = static_cast<int>(_Data);

baseData[index] = _value;

I am leaning towards the operator[] version as I see no real difference and it is much less code. Please advise and thank you all in advance.

insert and operator[] are both very useful methods. They appear similar, however, the details make them very different.

operator[]

Returns a reference to the element you are searching for. When no element exists, it creates a new default element. (So requires default constructor)

When used to insert an element: myMap[key] = value; , the value will override the old value for the key.

insert

Returns an iterator and a bool. The iterator is to the element. The bool indicates if a new element was inserted (true), or it already contained an element for the key (false).

Using insert doesn't require a default constructor.

When used to insert a new element: myMap.insert({key, value}); , the old value does not get updated if key already exists in the map.

insert_or_assign

Tnx to Marc Glisse who mentioned it in the comments.

This method is similar to insert . The difference is in the behavior when the element already exists, in which case it will override the existing element.

Returns an iterator and a bool. The iterator is to the element. The bool indicates if a new element was inserted (true), or it already contained an element for the key (false).

Using insert_or_assign doesn't require a default constructor.

When used to insert a new element: myMap.insert({key, value}); , the old value gets updated if key already exists in the map.

Building your map

Your use-case inserts data into the map and assumes that the key doesn't exist. Writing baseData[index] = _value; will exactly do what you want.

However, if I would have to write it, I would go with the insert variant:

auto successfulInsert = baseData.emplace(SC_val, _value).second;
assert(successfulInsert && "Value has been inserted several times.");

Just using operator [] perfectly fits for your case.

FYI: Quote from cppreference.com std::unordered_map :

std::unordered_map::operator[]
Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.

I see no real difference and it is much less code.

You're right!

It seems that you want to insert data only when it is not exist in the baseData. You can use count() to check if the data is in the map like this:

int index = static_cast<int>(_Data);
if(!baseData.count(index))
{
  baseData[index] = _value
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM