繁体   English   中英

std :: map operator [] - 未定义的行为?

[英]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是用户定义的类类型,并且编译器不会对重载的运算符进行翻译。 对于具有用户定义的类类型的ab对象:

  • a+=b并不意味着a = a + b (除非你这样做)
  • a!=b不代表!(a==b) (除非你这样做)

此外,函数调用永远不会重复。

所以m[10] += 1; 表示调用重载operator[]一次; return类型是一个引用,所以表达式是一个左值; 然后将内置运算符+=应用于左值。

没有评估问题的顺序。 甚至没有多个可能的评估订单!

此外,您需要记住std::map<>::operator[]行为不像std::vector<>::operator[] (或std::deque的),因为map是完全不同的抽象: vectordeque是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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM