增加的变量在递归调用中可重用吗?

3
我了解到,对已经进行后置递增的变量进行再次使用是函数调用中的未定义行为。我的理解是这在构造函数中不是问题。我的问题是关于tie,它奇怪地处于两者之间。
假设: pair<int, int> func(),我能做到:
tie(*it++, *it) = func();

或者那是未定义的行为?


3
std::tie 一个函数。我不认为它会有什么不同。 - super
1
在C++17中,这不再是未定义行为——尽管第二个参数是增加后的值还是原始值是未指定的 - Davis Herring
@DavisHerring 这不是根据定义来看是未定义行为吗? - Jonathan Mee
@JonathanMee:这也不是(称为实现定义);每次调用都会发生其中之一的行为,甚至在循环中多次调用之间也没有一致性的保证。 (实际上,在一个编译器版本内变化是相当不可能的,但是随着代码的任何更改,它很可能会发生变化。) - Davis Herring
1
@JonathanMee:不,因为您没有使用大括号初始化列表。如果使用括号,构造也无法获得排序保证。 - Ben Voigt
显示剩余3条评论
1个回答

3
自从 C++17 开始,此代码的行为是未指定的。有两种可能的结果:
- 第一个参数是原始迭代器解引用的结果,第二个参数是增加后迭代器解引用的结果; - 第一个参数和第二个参数都是原始迭代器解引用的结果。
根据 [expr.call]/8: > [...] 初始化参数(包括每个相关值计算和副作用)在与任何其他参数相比时具有不确定的顺序。[...]
因此,`tie` 的第二个参数可以是增加后迭代器解引用的结果或原始迭代器的结果。
在C++17之前,情况有点复杂:
- 如果`++`和`*`都调用一个函数(例如,当`it`的类型是一个复杂的类时),那么行为是未指定的,类似于自C++17以来的情况; - 否则,行为是未定义的。
根据N4140(C++14草案)[expr.call]/8
"[注意:后缀表达式和参数的求值相对于彼此都是无序的。所有参数求值的副作用在进入函数之前被排序(见[intro.execution])。—end note]"
因此,代码的行为是未定义的,因为一个参数的评估与另一个参数的评估是无序的。两个参数的评估可能重叠,导致数据竞争。除非另有规定...

根据 N4140 [intro.execution]/15

在调用函数时(无论该函数是否为内联函数),与任何参数表达式或指定被调用函数的后缀表达式相关的每个值计算和副作用都会在调用函数体中的每个表达式或语句执行之前进行排序。[注意:与不同参数表达式相关的值计算和副作用是无序的。--结束语] 在调用函数体的执行之前,调用函数中的每个评估(包括其他函数调用)如果没有特别排序,则与调用函数的执行无序排序。C++中的几个上下文会导致函数调用的评估,即使翻译单元中没有相应的函数调用语法也是如此。[例如:新表达式的评估会调用一个或多个分配和构造函数;参见[expr.new]。对于另一个例子,在没有函数调用语法出现的情况下,可以在转换函数([class.conv.fct])的调用中出现。-结束示例] 上述调用函数的执行排序约束条件是函数调用作为评估的特征,无论调用函数的表达式语法如何。换句话说,函数执行不会互相交错。
因此,如果操作符实际上是函数调用,则行为同样未指定。

1
@M.M 如果第二个参数先被评估会怎样? - L. F.
1
函数体的执行顺序是不确定的(或者使用C++11之前的术语,函数的入口和出口都有一个入口点,换言之,函数体不能交错执行)。即使f和g都通过引用修改x或访问全局变量等情况,foo(f(x),g(x));也是完全可以的。 - M.M
1
就像 operator++ 作为函数可以防止操作重叠/交错一样,一元运算符 operator* 成为一个函数也是足够的(那么 operator++ 就不需要了),这难道不是可以的吗?(注意,根据 as-if 规则,编译器实际上允许交错多个函数调用,只要按照顺序一致性规则的结果与某些允许的非重叠顺序相同即可)。 - Ben Voigt
1
@L.F. 我想你是指另一个参数中的 operator*?因为第一个参数中的 operator* 明显在 operator++ 的值计算之后被排序。但如果这是未定义的,那么只有 operator++ 是函数的情况也是如此,因为它可能会在另一个操作数的解引用过程中被调用。解引用被增量中断似乎和不完整的增量一样有害。所以我想你需要两个都是函数。 - Ben Voigt
1
你在编辑中很好地应用了德摩根定理,但我印象中我们倾向于如果两个都是函数则使用“未指定”,否则使用“未定义”? - Ben Voigt
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接