I have a std::map<std::string,std::size_t>
of keys mapping counters. When I increment a counter, I don't know if it already exists. If yes, it is incremented. If not, it is set to 1. This is easy to do:
std::map<std::string,std::size_t> counters;
//...
auto c_it = counters.find(key);
if(c_it == counters.end())
counters.insert(key,1);
else
(*c_it)++;
This is a lot of code for a simple thing... I want to do this:
counters[key]++;
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.
I see two potential solutions:
std::size_t
forcing initialization to 0 when created with default constructor. Is there such a type in std
or boost
?std::allocator<std::pair<const Key,T>>
given as 4th template argument of std::map
. But I have no idea how to do it.Note: I use C++11 only (I don't want solutions for C++>=14)
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 thatstd::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.