According to cppreference.com, std::map::operator[]
for non-existing value does zero-initialization.
However, the same site does not mention zero-initialization for std::unordered_map::operator[]
, except it does have an example which relies on this.
Of course this is just a reference site, not the standard. So, is the code below ok or not?
#include <unordered_map> int main() { std::unordered_map<int, int> map; return map[42]; // is this guaranteed to return 0? }
The value object is value-initialized, not zero-initialized.
the unordered map will try to default initialize mystruct with the key 'x' and assign to my struct. if u wanna avoid this, use . at(key) if it doesn't exist it will throw an out_of_range exception , which you can catch it and handle.
As you might expect, an unordered_map returns the default value for the value type if the key is not found in the map (count[5] will return 0 in this case).
On the site you linked it says:
When the default allocator is used, this results in the key being copy constructed from key and the mapped value being value-initialized.
So the int
is value-initialized:
The effects of value initialization are:
[...]
4) otherwise, the object is zero-initialized
This is why the result is 0
.
Depending on which overload we're talking about, std::unordered_map::operator[]
is equivalent to [unord.map.elem]
T& operator[](const key_type& k) { return try_emplace(k).first->second; }
(the overload taking an rvalue-reference just moves k
into try_emplace
and is otherwise identical)
If an element exists under key k
in the map, then try_emplace
returns an iterator to that element and false
. Otherwise, try_emplace
inserts a new element under the key k
, and returns an iterator to that and true
[unord.map.modifiers]:
template <class... Args> pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
Interesting for us is the case of there being no element yet [unord.map.modifiers]/6:
Otherwise inserts an object of type
value_type
constructed withpiecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...)
(the overload taking an rvalue-reference just moves k
into forward_as_tuple
and, again, is otherwise identical)
Since value_type
is a pair<const Key, T>
[unord.map.overview]/2, this tells us that the new map element will be constructed as:
pair<const Key, T>(piecewise_construct, forward_as_tuple(k), forward_as_tuple(std::forward<Args>(args)...));
Since args
is empty when coming from operator[]
, this boils down to our new value being constructed as a member of the pair
from no arguments [pairs.pair]/14 which is direct initialization [class.base.init]/7 of a value of type T
using ()
as initializer which boils down to value initialization [dcl.init]/17.4. Value initialization of an int
is zero initialization [dcl.init]/8. And zero initialization of an int
naturally initializes that int
to 0 [dcl.init]/6.
So yes, your code is guaranteed to return 0…
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With