12

Consider the following code:

map<int,int> m;
for(int i=0;i<10000;++i) m[i]++;
for(int i=0;i<10000;++i) printf("%d",m[i]);

I thought the the values printed out would be undefined because primitive types doesn't have default constructor, but here I got 10000 1s every time I tested.

Why is it initialized?

Mat
  • 202,337
  • 40
  • 393
  • 406
Leo Lai
  • 863
  • 8
  • 17

4 Answers4

14

When invoking operator[] and the key is missing, the value is initialized using the expression mapped_type() which is the default constructor for class types, and zero initialization for integral types.

Joseph Garvin
  • 20,727
  • 18
  • 94
  • 165
  • 2
    Hmm actually, are you sure this is the answer? On [map::operator[]](http://www.cplusplus.com/reference/map/map/operator[]/) it says: " A call to this function is equivalent to: (*((this->insert(make_pair(k,mapped_type()))).first)).second" which suggests the value-initialization of pair doesn't matter – Chris Beck Jul 24 '16 at 05:50
  • 2
    Are you sure with cplusplus.com? – LogicStuff Jul 24 '16 at 06:08
  • 1
    Chris has a point. The default constructor of `pair` obviously is not used - the `first` member of the pair is the integer index `i` which runs from 0 to 10000 here. If the default ctor would have been used, the `first` member would have been zero, and as a map can't contain duplicate keys there would have only a single map entry. As we know that 10000 ones were printed, we know the default pair ctor was not used. – MSalters Jul 24 '16 at 08:50
  • 1
    @ChrisBeck: you're right I wasn't thinking about which version of the constructor would be called, but the call to `mapped_type()` is going to do the same thing, no? I think in order to have an uninitialized value you would have to go out of your way in your map implementation to do something like an uninitialized value on the stack and then explicitly pass it into make_pair. So I guess the correct answer is that map is just always guaranteed to default construct the value type when the key is missing, and that default constructors for primitive types always zero initialize? – Joseph Garvin Jul 24 '16 at 18:52
  • 2
    Yeah, sounds right to me. I guess I would just say "when the key is missing, the value is initialized using the expression `mapped_type()` which is default ctor for class types, and zero initialization for integral types." – Chris Beck Jul 24 '16 at 19:56
5

std::map::operator[] inserts new value if it's not exist. If an insertion is performed, mapped value is initialized by default-constructor for class-types or zero-initialized otherwise.

Nikita
  • 6,270
  • 2
  • 24
  • 37
3

See https://www.sgi.com/tech/stl/stl_map.h

  _Tp& operator[](const key_type& __k) {
    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, _Tp()));
    return (*__i).second;
  }

In your example, _Tp is int, and int() is 0

#include <iostream>
using namespace std;
int main() {
  int x = int();
  cout << x << endl;
  return 0;
}

In addition:

thanks to @MSalters who tells about code above is SGI instead of std::map, But I think it is some like...

kaitian521
  • 548
  • 2
  • 10
  • 25
  • That's actually the STL `map` class, not `std::map`. The latter was inspired by the former, but there are minor differences. And this question is about a minute detail. But yes, as it happens there are no differences right here. – MSalters Jul 24 '16 at 08:47
  • you are right, there are many stl versions, SGI, STLPort, microsoft version, etc. – kaitian521 Jul 24 '16 at 08:58
  • If Microsoft ever had a STL-derived library, it was 2 decades ago. (VC4 perhaps, don't recall the details). They definitely switched to Dinkumware's implementation by VC6, a C++98 Standard Library implementation. – MSalters Jul 24 '16 at 09:05
  • How time flies! when I last used VC6 I was in my Colloege, 9 years ago... – kaitian521 Jul 24 '16 at 09:13
0

In the C++14 standard, section [map.access] the text is:

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.

So, as also stated by Joseph Garvin's answer, the result of the expression mapped_type() is what is inserted. This sort of initialization is called value-initialization.

The meaning of value-initialization is not quite as simple as offered in the other answers, for class types. It depends on what sort of constructors the class type has, and whether the class is an aggregate, as explained by the cppreference link.

For int as in this question, value-initialization means the int is set to 0.

M.M
  • 138,810
  • 21
  • 208
  • 365