If I do:
std::map<string, size_t> word_count;
size_t value = word_count.count("a") == 0 ? 1 : 2;
word_count["a"] = value;
then the final value of word_count["a"] is 1, as I would expect. If instead I do:
std::map<string, size_t> word_count;
word_count["a"] = word_count.count("a") == 0 ? 1 : 2;
then the final value of word_count["a"] is 2. Why!?
Officially, either side of the assignment could be evaluated first. It's up to the implementation to decide which. If word_count
does not contain an "a"
, one is inserted, and an lvalue reference to it returned. If word_count
does contain one, only the latter part happens. Despite the uncertainty of which side is evaluated first, you can follow possible executions:
operator[]
inserts the element since it isn't already there. count()
finds it and returns 1, so you end up with it being assigned a value of 2.
operator[]
returns the existing element and count()
finds it and returns 1, so you end up with it being assigned a value of 2.
count()
returns 0, so you get 1 from the right side. Then, "a"
is inserted into the map and assigned a value of 1.
count()
returns 1, so you get 2 from the right side. Then, word_count["a"]
is accessed and has 2 assigned to it.
In short, you can't rely on this to do what you want, so it's better to use something that you can rely on. mrfontanini made a good suggestion, so I'll edit it a bit:
word_count["a"]++;
word_count["a"] = std::min(word_count["a"], 2);
The first line ensures it is inserted and has a value of at least 1. The second limits that value to a maximum 2, in the case that you do this operation repeatedly.
I base this answer off of two things:
When a side is picked to be evaluated, the whole side has to be evaluated before the other side can start.
Constructs such as word_count["a"] = 1
exhibit well-defined behaviour, even in the case that an element is inserted and then assigned to.
There is some debate and discussion below about whether these are true or not. I've made it a bit more official now.
Looking at this line:
word_count["a"] = word_count.count("a") == 0 ? 1 : 2;
I believe that if word_count["a"]
does not exist in the map before that line is executed, you cause undefined behavior.
This is because word_count["a"]
will create an entry in the map if one doesn't exist, and this will change the behavior of word_count.count("a")
. We also have no required sequencing between those two calls..
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