c++sequence-pointsunspecified-behavior

Is inserting map size as value into a map undefined behavior?


edit: this question should have not been closed, if you look at the answers you will see they are totally different(old question has no mention of C++17).

I was reading a PVS blog post where they mention the following bug.

(reduced)

std::map<int,int> m;
m[7]=5;
auto val = 15;
if (!m.contains(val)){
    m[val] = m.size(); // bug here
}

According to blog post this is buggy. I always thought that operator [] call for map is a function call so .size() is sequenced before [] because functions act as sequence point.

So why is this a bug?

note: I know sequence points do not exist since C++11, but I use them since new wording is much harder for me to understand.


Solution

  • Pre C++17

    § 1.9 Program execution [intro.execution] (n3690 c++14 draft)

    1. Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.

    and 5.17 [expr.ass] doesn't mention any sequencing between the operands of built-in assignment. So the evaluation of the two operands of the built-in assignment operator = is unsequenced with regards to each other.

    m[val] and m.size() can be evaluated in any order (can even overlap - interleaved the CPU instructions).

    Considering:

    § 1.9 Program execution [intro.execution] (n3690 c++14 draft)

    1. [...] If a side effect on a scalar object is unsequenced relative to either [...] or a value computation using the value of the same scalar object, the behavior is undefined.

    So yes, the behavior is indeed Undefined.

    C++17

    §8.5.18 Assignment and compound assignment operators [expr.ass] (n4713 C++17 draft)

    1. The assignment operator (=) [...] The right operand is sequenced before the left operand.

    So the behavior is defined. m.size() will be evaluated before m[val]