115

Possible Duplicate:
In STL maps, is it better to use map::insert than []?

I was wondering, when I insert element into map, what is the recommended way. Should I

map[key] = value;

or

map.insert(std::pair<key_type, value_type>(key, value));

I did the following quick test:

#include <map>
#include <string>
#include <iostream>

class Food {
public:
    Food(const std::string& name) : name(name) { std::cout << "constructor with string parameter" << std::endl; }
    Food(const Food& f) : name(f.name) { std::cout << "copy" << std::endl; }
    Food& operator=(const Food& f) { name = f.name; std::cout << "=" << std::endl; return *this; } 
    Food() { std::cout << "default" << std::endl; }
    std::string name;
};

int main() {
    std::map<std::string, Food> m0;

/*
1) constructor with string parameter
2) copy
3) copy
4) copy
*/
    m0.insert(std::pair<std::string, Food>("Key", Food("Ice Cream")));

/*
1) constructor with string parameter
2) default
3) copy
4) copy
5) =
*/
    // If we do not provide default constructor.
    // C2512: 'Food::Food' : no appropriate default constructor available
    m0["Key"] = Food("Ice Cream");
}
  1. I realize by using member function insert, less value's function call will be involved. So, is using insert a recommended way?
  2. Why default constructor is needed, when map[key] = value way is being used?

I know that insert doesn't overwrite existence key value pair, but map[key] = value does. However, is this the only factor I take into consideration, when try to choose among the both?

How about

  1. Performance
  2. Availability of value's default constructor
  3. ???
Community
  • 1
  • 1
Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875
  • 4
    unless you can see there is a serious performance hit, why bother with all the typing of the first one? also, a decent optimizer might get rid of some of the copies – stijn Aug 05 '11 at 06:54
  • 1
    Why not look at it this way: if you never expect duplicate values use `insert` otherwise use `map[key] = value` – Ioan Paul Pirau Aug 05 '11 at 07:23

4 Answers4

85
  1. insert is not a recommended way - it is one of the ways to insert into map. The difference with operator[] is that the insert can tell whether the element is inserted into the map. Also, if your class has no default constructor, you are forced to use insert.
  2. operator[] needs the default constructor because the map checks if the element exists. If it doesn't then it creates one using default constructor and returns a reference (or const reference to it).

Because map containers do not allow for duplicate key values, the insertion operation checks for each element inserted whether another element exists already in the container with the same key value, if so, the element is not inserted and its mapped value is not changed in any way.

KyleL
  • 855
  • 6
  • 24
BЈовић
  • 62,405
  • 41
  • 173
  • 273
  • 19
    This does not mention the most important difference, if an element is already present insert does not do anything. – Sverre Rabbelier Aug 05 '11 at 09:06
  • That's all good, but it doesn't help me force insert without creating a no-argument constructor. Can I do that… without an insert, check, delete, insert? – Mihai Danila May 19 '17 at 17:42
55

Use insert if you want to insert a new element. insert will not overwrite an existing element, and you can verify that there was no previously exising element:

if ( !myMap.insert( std::make_pair( key, value ) ).second ) {
    //  Element already present...
}

Use [] if you want to overwrite a possibly existing element:

myMap[ key ] = value;
assert( myMap.find( key )->second == value ); // post-condition

This form will overwrite any existing entry.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
13

To quote:

Because map containers do not allow for duplicate key values, the insertion operation checks for each element inserted whether another element exists already in the container with the same key value, if so, the element is not inserted and its mapped value is not changed in any way.

So insert will not change the value if the key already exists, the [] operator will.

EDIT:

This reminds me of another recent question - why use at() instead of the [] operator to retrieve values from a vector. Apparently at() throws an exception if the index is out of bounds whereas [] operator doesn't. In these situations it's always best to look up the documentation of the functions as they will give you all the details. But in general, there aren't (or at least shouldn't be) two functions/operators that do the exact same thing.

My guess is that, internally, insert() will first check for the entry and afterwards itself use the [] operator.

Guy Avraham
  • 3,482
  • 3
  • 38
  • 50
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • Actually, it's vice versa, at least in GNU libstdc++: `operator[]` looks for existing element and calls `insert` with default constructed value if not found. – vaclav.blazek Mar 06 '20 at 10:39
11

map[key] = value is provided for easier syntax. It is easier to read and write.

The reason for which you need to have default constructor is that map[key] is evaluated before assignment. If key wasn't present in map, new one is created (with default constructor) and reference to it is returned from operator[].

x13n
  • 4,103
  • 2
  • 21
  • 28