[英]std::map operator [] — undefined behaviour?
我只是坚持以下问题:这是否会导致未定义的行为,为什么?
std::map<int, int> m;
m[10] += 1;
它编译和运行完美,但它没有任何证据。 它类似于常见的UB示例i = ++i + i++;
因为operator[]
确实有副作用但另一方面假设任何评估顺序(从左到右和从右到左)使我进入地图的相同最终状态
PS可能相关: http : //en.cppreference.com/w/cpp/language/eval_order
编辑
对不起,我应该写的
m[10] = m[10] + 1;
没有什么不确定的。 operator[]
返回对映射条目的左值引用(如果需要,它将创建它)。 然后,您只是递增此左值表达式,即基础条目。
评估顺序的规则规定,对于修改分配操作,在评估左(即左值参考映射条目)和右(即常数1
)操作数之后,严格地对副作用进行排序。 在这个例子中根本没有歧义。
更新:在您更新的示例中没有任何更改。 同样,修改m[10]
的副作用在其他操作之后严格排序(即在右侧评估为左值,在右侧评估它,并执行添加)。
相关的排序规则,来自cppreference :
8)内置赋值运算符和所有内置复合赋值运算符的副作用(左参数的修改)在左右参数的值计算(但不是副作用)之后排序,并且是在赋值表达式的值计算之前(即,在返回对修改对象的引用之前)排序
我不太确定你的担心是什么(也许你应该澄清你的问题,如果答案不充分),但m[10] += 1;
没有被翻译成m[10] = m[10] + 1;
因为m
是用户定义的类类型,并且编译器不会对重载的运算符进行翻译。 对于具有用户定义的类类型的a
和b
对象:
a+=b
并不意味着a = a + b
(除非你这样做) a!=b
不代表!(a==b)
(除非你这样做) 此外,函数调用永远不会重复。
所以m[10] += 1;
表示调用重载operator[]
一次; return类型是一个引用,所以表达式是一个左值; 然后将内置运算符+=
应用于左值。
没有评估问题的顺序。 甚至没有多个可能的评估订单!
此外,您需要记住std::map<>::operator[]
行为不像std::vector<>::operator[]
(或std::deque
的),因为map
是完全不同的抽象: vector
和deque
是Sequence概念的实现(其中position很重要),但map
是一个关联容器(其中“key”很重要,而不是位置):
std::vector<>::operator[]
采用数字索引,如果这样的索引不引用向量的元素,则没有意义。 std::map<>::operator[]
接受一个键(可以是满足基本约束的任何类型), 如果不存在 , 将创建一个(键,值)对 。 请注意,出于这个原因, std::map<>::operator[]
本质上是一个修改操作,因此是非const ,而std::vector<>::operator[]
本身并不是修改,但可以通过返回引用,因此是“传递”const:如果v
是非常量向量,则v[i]
将是可修改的左值,如果v
是常量向量,则是v
值。
所以不用担心,代码具有完美定义的行为。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.