chr*_*ris 4 c++ operator-precedence undefined-behavior sequence-points unspecified-behavior
在回答了这个问题之后,对于有问题的代码是否是未定义的行为进行了长时间的讨论.这是代码:
std::map<string, size_t> word_count;
word_count["a"] = word_count.count("a") == 0 ? 1 : 2;
Run Code Online (Sandbox Code Playgroud)
首先,至少没有具体说明这一点已经确定.结果根据首先评估分配的哪一侧而不同.在我的回答中,我跟踪了四个结果案例中的每一个,其中包括首先评估哪一方的因素以及该元素之前是否存在.
还有一个简短的表格:
(x = 0) = (x == 0) ? 1 : 2; //started as
(x = 0) = (y == "a") ? 1 : 2; //changed to
Run Code Online (Sandbox Code Playgroud)
我声称它更像是这样的:
(x = 0, x) = (x == 0) ? 1 : 2; //comma sequences x, like [] should
Run Code Online (Sandbox Code Playgroud)
最后,我找到了一个似乎对我有用的例子:
i = (++i,i++,i); //well-defined per SO:Undefined Behaviour and Sequence Points
Run Code Online (Sandbox Code Playgroud)
回到原文,我把它分解成相关的函数调用,以便更容易理解:
operator=(word_count.operator[]("a"), word_count.count("a") == 0 ? 1 : 2);
^ inserts element^ ^reads same element
|
assigns to element
Run Code Online (Sandbox Code Playgroud)
如果word_count["a"]不存在,则有人认为它将被分配两次,而两者之间没有排序.我个人没有看到如果我认为真实的两件事实际上是如何发生的:
当选择要评估的一侧时,必须在另一侧开始之前评估整个侧面.
诸如word_count ["a"] = 1之类的构造表现出明确定义的行为,即使在插入元素然后分配元素的情况下也是如此.
这两个陈述是真的吗?最终,实际上是未定义的行为,如果是,为什么第二个语句有效(假设确实如此)?如果第二个是假的,我相信myMap[i]++;世界上所有的人都会是不正确的.
有用的链接:未定义的行为和序列点
行为未指定,但未定义.
请注意,在表达式中:
word_count["a"] = word_count.count("a") == 0 ? 1 : 2;
// ^
Run Code Online (Sandbox Code Playgroud)
标有赋值运算符^是内置的赋值操作符,因为std::map的operator []返回size_t&.
根据内置赋值运算符的C++ 11标准的第5.17/1段:
赋值运算符(=)和复合赋值运算符都是从右到左分组.[..] 在所有情况下,赋值在右和左操作数的值计算之后,以及赋值表达式的值计算之前排序.对于不确定序列的函数调用,复合赋值的操作是单个评估.
这意味着在内置赋值中,例如:
a = b
Run Code Online (Sandbox Code Playgroud)
首先评估操作数(以未指定的顺序),然后执行赋值,最后执行整个赋值表达式的值计算.
考虑原始表达:
word_count["a"] = word_count.count("a") == 0 ? 1 : 2;
// ^
Run Code Online (Sandbox Code Playgroud)
由于上面引用的段落,在任何情况下都不会对同一个对象进行两次无序分配:标记的赋值^将始终在执行赋值后operator [](作为左侧表达式的求值的一部分)在键的情况下排序"a"在地图中不存在.
但是,根据首先评估分配的哪一方,表达式将具有不同的结果.因此,行为未指定,但未定义.