C++: conditionally inserting a key and value into a std::map

c++

Solution

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:

Left Side First

No Element Exists:

`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.

Element Exists:

`operator[]` returns the existing element and `count()` finds it and returns 1, so you end up with it being assigned a value of 2.

Right Side First

No Element Exists:

`count()` returns 0, so you get 1 from the right side. Then, `"a"` is inserted into the map and assigned a value of 1.

Element Exists:

`count()` returns 1, so you get 2 from the right side. Then, `word_count["a"]` is accessed and has 2 assigned to it.

Conclusion

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.

Notes

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.

Problem

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!?

Original source

Related problems