Do Stl Maps Initialize Primitive Types on Insert

Do STL maps initialize primitive types on insert?

operator[] looks like this:

Value& map<Key, Value>::operator[](const Key& key);

If you call it with a key that's not yet in the map, it will default-construct a new instance of Value, put it in the map under key you passed in, and return a reference to it. In this case, you've got:

map<wstring,int> Scores;
Scores[wstrPlayerName]++;

Value here is int, and ints are default-constructed as 0, as if you initialized them with int(). Other primitive types are initialized similarly (e.g., double(), long(), bool(), etc.).

In the end, your code puts a new pair (wstrPlayerName, 0) in the map, then returns a reference to the int, which you then increment. So, there's no need to test if the element exists yet if you want things to start from 0.

Is the value of primitive types in std::map initialized?

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.

Why are entries of this STL map not being initialized in GCC 4.5.1?

As one would expect, the code excerpt is a simplified version of what's really going on. It turns out that a find command is used on the map, so that essentially map.find(1)->second is being called, instead of simply map[1]. This explains the undefined behavior.

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

When you write

map[key] = value;

there's no way to tell if you replaced the value for key, or if you created a new key with value.

map::insert() will only create:

using std::cout; using std::endl;
typedef std::map<int, std::string> MyMap;
MyMap map;
// ...
std::pair<MyMap::iterator, bool> res = map.insert(MyMap::value_type(key,value));
if ( ! res.second ) {
cout << "key " << key << " already exists "
<< " with value " << (res.first)->second << endl;
} else {
cout << "created key " << key << " with value " << value << endl;
}

For most of my apps, I usually don't care if I'm creating or replacing, so I use the easier to read map[key] = value.

Does STL Map auto-initialize values?

Quoth the standard:

ISO/IEC 14882 §23.4.4.3

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.
  2. Requires: key_type shall be CopyConstructible and mapped_type shall be DefaultConstructible.
  3. Returns: A reference to the mapped_type corresponding to x in *this.
  4. Complexity: logarithmic.

So, not only is it guaranteed, but evaluating myMap["Hey"] also causes the value 0 to be inserted into the map, if there was no entry for it before.

initialize part of a const std::map from another const std::map

While @Rakete111's answer is perfectly valid for what you need, I suggest elevating that to a function. Maybe you can use it multiple places.

std::map<int, std:::string> combine(std::map<int, std::string> const& map1,
std::map<int, std::string> const& map2)
{
std::map<int, std:::string> res(map1);
res.insert(map2.begin(), map2.end());
return res;
}

and then use

const auto secondMap = combine(firstMap,
std::map<int, std::string>{{3, "Third"}});

Force initialization to 0 when inserting into a std::map

But this generates undefined behavior because std::size_t() is called when the counter doesn't exist in the map, and there is no guarantee that std::size_t() initializes to 0.

This assumption is incorrect. Quote from cppreference:

If an insertion is performed, the mapped value is value-initialized (default-constructed for class types, zero-initialized otherwise) and a reference to it is returned.

The quote is for pre-C++11 version, but it's easier to understand that the tuple magics and the observable effect is the same.

The value will be zero-initialized, you can use counters[key]++; without issues.

std::map operator[] and automatically created new objects

The new object, when inserted into the map by [] operator, is value-initialized. It is ensured by the map implementation, i.e. it is done "automatically" in that sense. For objects of type DWORD (assuming it is a scalar type), value-initialization means zero-initialization.

By definition given in 23.3.1.2, operator [] is a shorthand for

(*((insert(make_pair(x, T()))).first)).second

The T() bit is the new object, which will turn into DWORD() in your case. DWORD() is guaranteed to be zero.

std::map default value for build-in type

This is defined in the standard, yes. map is performing "default initialization" in this case. As you say, for class types, that calls a no-arguments constructor.

For built-in types, in the '98 standard, see section 8.5, "Initializers":

To default-initialize an object of type T means:

  • if T is a non-POD ...
  • if T is an array type ...
  • otherwise, the storage for the object is zero-initialized

And, previously,

To zero-initialize storage for an object of type T means:

  • if T is a scalar type, the storage is set to the value 0 (zero) converted to T

Scalar types are:

  • Arithmetic types (integer, floating point)
  • Enumeration types
  • Pointer types
  • Pointer to member types

In particular, the behaviour you see with an integer (initialized to zero) is defined by the standard, and you can rely on it.



Related Topics



Leave a reply



Submit