Let's say I have a std::map<int, int>
, would it be safe to do this?
std::map<int, int> m_map;
m_map[0] += 1;
If the key 0
didn't exist in the map when I do this, how would it know what value to add 1
to?
What I'm hoping is that std::map handles this by performing an =
instead of +=
in the case where the value creates a new entry in the map. This would spare me from having to do:
std::map<int, int>::iterator it = m_map.find(0);
if(it != m_map.end()) {
it->second += 1;
}
else {
m_map[0] = 1;
}
If you want to insert element in std::map - use insert() function, and if you want to find element (by key) and assign some to it - use operator[].
Time complexity: k*log(n) where n is size of map, k is no. of elements inserted.
Starting with C++17, we can use the std::map::merge member function to copy content from a map to another map. This is the recommended way to copy the contents of a map to an existing map in C++17 and above. That's all about copying entries of a map to another map in C++.
An element inserted into a map on invoke of operator[]
due to a previously-unmapped key is value-initialized. If you've not seen that syntax, consider the special meaning the ()
has in the following code snippet. The parens are important. They introduce an different trip down the initialization tree than default-initialization. Both are important; both are laid out by the language standard.
int i = int();
As it turns out, value initialization for scalars (including pointers) eventually succumbs to zero-initialization. Though odd looking, the prior snippet value-initializes an instance of int
, which becomes zero-initialization since int
is a scalar, then copies it to i
. (To be fair, there will almost certainly be some eliding, but the fundamentals are as-presented).
Regardless, due to that feature, you can rest assured when you do this:
m_map[0] += 1;
or even this:
++m_map[0];
if the index wasn't mapped prior, a value-initialized element is added, which will zero-initialize for scalars, which means you'll officially starting out with zero.
It is worth mentioning that a similar activity happens for any type with an implicitly declared constructor. Whether trivial or not, something interesting happens.
struct S { int a; int b; };
std::map<int, S> mymap;
++mymap[0].a;
Is the a
member mapped to 0
in our container reliably 1
after the above executes? Yes, it is. Further, consider this:
struct S { int a; std::string str; };
std::map<int, S> mymap;
++mymap[0].a;
Now S
has a non-trivial implicit constructor (it has to, as it must construct str
). But is the a
member mapped to 0
in our container still reliably zero-initialized (and therefore 1
after the above line)? Yes, it is.
If curious about the referenced different paths of initialization, see this question and answer. Or review the C++11 standard, particularly C++11 § 8.5 Initializers, (p5,p7,p10). It is worth the read.
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