After answering this question, there was a long discussion over whether the code in question was undefined behaviour or not. Here's the code:
std::map<string, size_t> word_count;
word_count["a"] = word_count.count("a") == 0 ? 1 : 2;
First of all, it was well-established that this was at least unspecified. The result differs based on which side of the assignment is evaluated first. In my answer, I followed through each of the four resulting cases, with factors of which side is evaluated first and whether the element exists prior to this.
There was a short form that came up as well:
(x = 0) = (x == 0) ? 1 : 2; //started as
(x = 0) = (y == "a") ? 1 : 2; //changed to
I claimed it was more like this:
(x = 0, x) = (x == 0) ? 1 : 2; //comma sequences x, like [] should
Eventually, I found an example that seemed to work for me:
i = (++i,i++,i); //well-defined per SO:Undefined Behaviour and Sequence Points
Back to the original, I broke it down into relevant function calls to make it easier to follow:
operator=(word_count.operator[]("a"), word_count.count("a") == 0 ? 1 : 2);
^ inserts element^ ^reads same element
|
assigns to element
If word_count["a"]
does not exist, it was argued that it would be assigned to twice without a sequencing in between. I personally didn't see how that could happen if two things I thought were true actually were:
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.
Are these two statements true? Ultimately, is that actually undefined behaviour, and if it is, why does the second statement work (assuming it does)? If the second is false, I believe all the myMap[i]++;
s in the world would be ill-formed.
Helpful Link: Undefined behavior and sequence points