Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why C++ map.insert() doesn't overwrite

Tags:

c++

In the code below:

#include <map>
#include <utility>
#include <iostream>

using namespace std;

int main(){
  pair<int,int> p1(1,1);
  pair<int,int> p2(1,2);

  map<int,int> m;
  m.insert(p1);
  m.insert(p2);

  cout << "Map value: "<< m.at(1) << endl;

}

It printed out : Map value: 1, why m.insert(p2) doesn't overwrite the previous entity in the map?

like image 893
user4177980 Avatar asked Oct 24 '14 14:10

user4177980


People also ask

Does insert overwrite map C++?

insert() doesn't overwrite.

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.

Does map insert make a copy?

Yes -- when you insert an item into an std::map, you pass it by value, so what it contains is a copy of what you passed.

How do you add elements to a map?

The standard solution to insert new elements into a map is using the std::map::insert function. It inserts the specified key-value pair into the map only if the key already doesn't exist. If the key already exists in the map, the element is not inserted.


1 Answers

Update as of C++17 There is now the std::map::insert_or_assign() member function:

m.insert_or_assign(p1);

As the name suggests, if the key is already present then the value is assigned (and the key object kept) rather than erasing and freshly copy constructing the key and value. (So it's equivalent to the first of the two pre-C++17 snippets below.)

If you want an iterator pointing at the (new or updated) element, you again need to pick the value out of the returned pair. Since you're using C++17, you can now use a structured binding:

auto [it, wasInserted] = m.insert_or_assign(p1);

Before C++17 Putting together the other answers, if you want to avoid the assumption of being default constructable you get insert-with-overwrite code that looks like this:

auto itAndWasInserted = m.insert(p1);
if (!itAndWasInserted.second) {
    *(itAndWasInserted.first) = p1;
}

If you want to avoid copy construction, but also want to avoid a second seek (for re-insertion), you end up with this monster:

auto itAndWasInserted = m.insert(p1);
auto it = itAndWasInserted.first;
if (!itAndWasInserted.second) {
    auto afterIt = m.erase(it);
    auto newItAndWasInserted = m.insert(afterIt, p1);  // Hint form of insert
    it = newItAndWasInserted.first;
}

At the end of the code block, it is an iterator pointing at the just-inserted element.

Realistically, in most cases you probably just want to use yizzlez's suggestion of operator[], but I thought it would be good to note the theoretically best answer.

like image 82
Arthur Tacca Avatar answered Oct 05 '22 05:10

Arthur Tacca