【问题标题】:Is an Incremented Variable Reusable in a tie Call?在 tie 调用中增量变量是否可重用?
【发布时间】:2019-11-21 09:48:27
【问题描述】:

所以我知道重复使用后递增的变量是undefined behavior in a function call。我的理解是这在构造函数中不是问题。我的问题是关于 tie 的问题,奇怪的是,它介于两者之间。

鉴于:pair<int, int> func() 我能做到吗:

tie(*it++, *it) = func();

或者这是未定义的行为?

【问题讨论】:

  • std::tie 一个函数。我不明白为什么会有所不同。
  • 在 C++17 中,这不再是 UB——尽管第二个参数是否为递增值是未指定
  • @DavisHerring 这不是 UB 的定义吗?
  • @DavisHerring 啊……我真的很喜欢那些鼻恶魔。所以我想我们是说现在编译器定义了它将如何表现?真的同样困难,只是可能没有那么灾难性。
  • @JonathanMee:不,因为您没有使用花括号初始化列表。如果使用括号,构造也不会得到排序保证。

标签: c++ increment undefined-behavior function-call tie


【解决方案1】:

自 C++17 起,此代码具有未指定的行为。有两种可能的结果:

  • 第一个参数是解引用原迭代器的结果,第二个参数是解引用递增迭代器的结果;或

  • 第一个参数和第二个参数都是解引用原迭代器的结果。

[expr.call]/8:

[...] 参数的初始化,包括每个相关的 价值计算和副作用,是不确定的 相对于任何其他参数。 [...]

所以tie 的第二个参数可能是取消引用递增迭代器或原始迭代器的结果。


在C++17之前,情况有点复杂:

  • 如果++* 都调用了一个函数(例如,当it 的类型是一个复杂的类时),那么行为是未指定,类似于C++17 以后的情况;

  • 否则,行为未定义

根据 N4140(C++14 草案)[expr.call]/8

[ 注意: 后缀表达式和 论点彼此之间都是无序的。 所有方面 参数评估的效果在函数被排序之前被排序 输入(参见 [intro.execution])。 — 尾注 ]

因此,代码是未定义的行为,因为对一个参数的评估未与另一个参数进行排序。这两个参数的评估可能会重叠,从而导致数据竞争。除非另有说明......

根据 N4140 [intro.execution]/15:

调用函数时(无论函数是否内联),每个 与任何参数相关的值计算和副作用 表达式,或带有指定被调用者的后缀表达式 函数,在执行每个表达式之前排序或 被调用函数的主体中的语句。 [ 注意: 值 与不同参数相关的计算和副作用 表达式是无序的。 — 尾注 ] 每次评估 在调用函数(包括其他函数调用)中不是 否则在执行之前或之后特别排序 被调用函数的主体是不确定的 到被调用函数的执行。9几个 C++ 中的上下文会导致对函数调用进行评估,即使没有 相应的函数调用语法出现在翻译单元中。 [ 示例: 对新表达式的求值会调用一个或多个分配和构造函数;见[expr.new]。为了另一个 例如,调用转换函数 ([class.conv.fct]) 可以 出现在没有出现函数调用语法的上下文中。 — 结束示例 ] 被调用函数的执行顺序约束(如上所述)是函数的特征 无论调用的表达式的语法是什么,都按评估调用 功能可能是。

9) 换句话说,函数执行不会与每个 其他。

因此,如果运算符实际上是函数调用,那么行为同样是未指定的。

【讨论】:

  • 你说“第一个参数是原始迭代器”,但是迭代器是被尊重的。可能的情况是参数必须是迭代器“点”的前 2 个位置,但可以是任意顺序
  • @M.M 如果先计算第二个参数怎么办?
  • 另一个细节:迭代器通常是类类型;所以++ 转换为函数调用,因此,在 C++17 之前,该行为是未指定的。如果迭代器是原始指针,它只会是 UB。
  • 函数体的顺序是不确定的(或者在 c++11 之前的术语中,函数的进入和退出有一个入口点,或者通俗地说,函数体不能交错)。 foo( f(x), g(x) ); 非常好,即使 f 和 g 都通过引用修改 x,或者访问全局变量。
  • 正如operator++ 是一个函数可以防止操作的重叠/交错一样,一元operator* 是一个函数还不够(然后operator++ 不需要是)? (注意,实际上允许编译器在 as-if 规则下交错多个函数调用,只要顺序一致性规则下的结果与某些允许的非重叠排序相同)
猜你喜欢
  • 2016-03-30
  • 1970-01-01
  • 2023-01-27
  • 2022-01-04
  • 1970-01-01
  • 2013-08-29
  • 2020-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多