I see a lot of examples that add items to a map
or unordered_map
via operator[]
, like so:
int main() {
unordered_map <string, int> m;
m["foo"] = 42;
cout << m["foo"] << endl;
}
Is there any reason to use the insert
member function instead? It would appear they both do the same thing.
They are not.
operator[]
will overwrite the value for this key, if it exists, while insert
will not.
In case operator[]
is used for inserting element, it is expected to be a little slower (see @MatthieuM's comment below for details), but this is not that significant here.
While std::map::insert
returns std::pair< iterator, bool >
, where the .second
will tell you if the value is inserted or it already exists.
Regarding your comment: you cannot have 2 elements with the same key and different value. This is not a multimap
.
If there's an element in the map, with the same key you're trying to insert, then:
operator[]
will overwrite the existing value std::map::insert
will std::pair< iterator, bool >
, where the .second
will be false
(saying "the new element is not inserted, as such key already exists") and the .first
will point to the found element.* I changed this thanks to the note/remark, given from @luk32; but by writing "will not do anything", I didn't mean it literally, I meant that it will not change the value of the existing element
Using insert()
can help improve performance in certain situations (more specifically for std::map
since search time is O(log(n))
instead of constant amortized). Take the following common example:
std::map<int, int> stuff;
// stuff is populated, possibly large:
auto iterator = stuff.find(27);
if(stuff.end() != iterator)
{
// subsequent "find", set to 15
iterator->second = 15;
}
else
{
// insert with value of 10
stuff[27] = 10;
}
The code above resulted in effectively finding the element twice. We can make that (slightly) more efficient written like this:
// try to insert 27 -> 10
auto result = stuff.insert(std::make_pair(27, 10));
// already existed
if(false == result.second)
{
// update to 15, already exists
result.first->second = 15;
}
The code above only tries to find an element once, reducing algorithmic complexity. For frequent operations, this can improve performance drastically.
The two are not equivalent. insert
will not overwrite an existing value, and it returns a pair<iterator, bool>
, where iterator
is the location of the key, regardless of whether or not it already existed. The bool
indicates whether or not the insert occurred.
operator[]
effectively does a lower_bound
on key. If the result of that operation is an iterator
with the same key, it returns a reference to the value. If not, it inserts a new node with a default-constructed value, and then returns a reference to the value. This is why operator[]
is a non-const member - it auto-vivifies the key-value if it doesn't exist. This may have performance implications if the value type is costly to construct.
Also note in C++11, we have an emplace
method that works nearly identical to insert
, except it constructs the key-value pair in-place from forwarded arguments, if an insert occurs.
Well I disagree with Kiril's answer to a certain degree and I think it's not full so I give mine.
According to cppreference
std::map::operator[]
is equivalent to a certain insert()
call. By this I also think he is wrong saying the value will be overwritten.
It says: "Return value
Reference to the mapped value of the new element if no element with key key existed. Otherwise a reference to the mapped value of the existing element is returned."
So it seems it is a convenient wrapper. The insert()
, however has this advantage of being overloaded, so it provides more functionality under one name.
I give a point to Kiril, that they do seem to have a bit different functionality at first glance, however IHMO the examples he provides are not equivalent to each other.
Therefore, as an example/reason to use insert
I would point out, inserting many elements at once, or using hint
( Calls 3-6 in here).
So is insert() necessary in a map or unordered_map?
I would say yes. Moreover, the operator[]
is not necessary as it can be emulated/implemented using insert
, while the other way is impossible! It simply provides more functinality. However, writing stuff like (insert(std::make_pair(key, T())).first)->second)
(after cppreference) seems cumbersome than []
.
Thus, is there any reason to use the insert member function instead? I'd say for overlapping functionality, hell no.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With