2

I have a friend at work who encouraged me to never assign a key/value pair into an empty map like the following:

int somefunc(map<int, int> somemap) {
    somemap.clear();
    somemap[12] = 42;
}

He said that since the somemap map variable was cleared, then somemap[12] is an invalid access. I reasoned that no C++ compiler, even when compiling in debug mode, would ever produce assembly that would unnecessarily try to access the somemap[12] on the assignment above. That it is always the case that the last line above would be compiled to the same assembly as this line:

somemap.insert(std::pair(12,42));

Is that true? Is there any reason to do assignment via insert vs. the earlier method? I prefer the earlier as it's shorter.

PentiumPro200
  • 641
  • 7
  • 23
  • 3
    `somemap[12]` will create it if it doesn't exist. No problem at all. – chris Dec 13 '13 at 19:03
  • I know it works as I used it all the time. However, his concern is that the assignment above is not supported by the C++ standard library / Visual Studio when run in debug mode or with some odd compile / link options enabled and that it could break in the future. I'm very skeptical of that claim, I just need a reason to convince him that the short assignment is save to use... – PentiumPro200 Dec 13 '13 at 19:09
  • which version of visual c++ is he using? – thermite Dec 13 '13 at 19:12
  • It's supported by at least C++98. – Elliot Robinson Dec 13 '13 at 19:14
  • We're using Visual Studio 2005 and later. – PentiumPro200 Dec 13 '13 at 19:35
  • http://stackoverflow.com/questions/6211926/which-standard-does-vs2005-vs2008-follow states that 2005 targets (perhaps poorly) the C++03 standard, which is an update to the C++98 standard (which mandates this notation). You should be in good shape. – Elliot Robinson Dec 13 '13 at 19:38
  • Thanks for all the responses. That's was far more input than I expected so I appreciate. I never had any doubts about the first assignment, I see it used all over the place. I just needed proof that it would not cause any problems. – PentiumPro200 Dec 13 '13 at 19:47
  • `int somefunc(map somemap) {` is taking the wrong type, it shouldbe takinga reference, not a copy, which is what this does. As it stands, no changes to this map will be visible outside of the funciton. – RichardPlunkett Dec 13 '13 at 21:01

6 Answers6

1

std::map overrides the [] operator to call .insert on non-existent keys. No problems here.

Elliot Robinson
  • 1,384
  • 7
  • 16
1

Yes, the last line will always insert an element, if it does not already exist.

From section 23.4.4.3 of the C++ standard:

T& operator[](const key_type& x);
  1. Effects: If there is no key equivalent to x in the map, inserts value_type(x, T()) into the map.

The map::[] operator is defined as:

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.

Steve
  • 7,171
  • 2
  • 30
  • 52
0

[] it's overloaded operator so code for it

    operator[](const key_type& __k)
    {
       // concept requirements
     __glibcxx_function_requires(_DefaultConstructibleConcept<mapped_type>)

      iterator __i = lower_bound(__k);
     // __i->first is greater than or equivalent to __k.
      if (__i == end() || key_comp()(__k, (*__i).first))
           __i = insert(__i, value_type(__k, mapped_type()));
      return (*__i).second;
   }

from here you can see that if it is empty it will be inserted

sim
  • 756
  • 6
  • 18
0

map's operator[] does the following:

  • find element (key). If found return a reference to it (value&).
  • If not found, create an empty element pair<key,value(default value)> and return a reference to the value.

The issue with operator[] is different. Some people want to use it for searching if an element exists or not. This is wrong since the map will fill up with empty elements. For searching people should use map.find().

egur
  • 7,830
  • 2
  • 27
  • 47
0

Both uses are valid with slightly different meanings:

somemap[12] = 42;

Will replace the existing value for somemap[12] if it exists, or insert a new value if it does not exist.

auto returnValue = somemap.insert<std::make_pair(12, 42));

will insert a new value for somemap[12] if one does not already exist, or leave the value unchanged if there is already a mapping for 12. You can tell if it worked like so:

if(returnValue.second)
{
   // it worked.  
   // returnValue.first is an iterator pointing to the newly added element
}
else
{
    // it failed.
    // returnvalue.first is an iterator pointing to the unchanged pre-existing element.
}
Dale Wilson
  • 9,166
  • 3
  • 34
  • 52
0

The best way is to measure. However, the library will locate the position for the key and, if it doesn't exist, add a new node with the key and a default constructed value. It then returns a reference to which the assignment is made: The library doesn't see the assigned value, i.e., it can not do the moral equivalent of

map.insert(std::make_pair(12, 42));

I'd be surprised if a compiler could detect that it could do this operation. For ints the difference doesn't really matter. For other types it shouldn't matter either, i.e., they should have an efficient default constructor.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380