所以我知道重新使用已后递增的变量是函数调用中的未定义行为。我的理解是这在构造函数中不是问题。我的问题是关于
tie
,奇怪的是,它介于两者之间。
鉴于:
pair<int, int> func()
我可以做什么:
tie(*it++, *it) = func();
或者这是未定义的行为?
自 C++17 起,此代码具有未指定的行为。 有两种可能的结果:
第一个参数是取消引用原始迭代器的结果,第二个参数是取消引用递增迭代器的结果;或
第一个参数和第二个参数都是取消引用原始迭代器的结果。
[...] 参数的初始化,包括每个关联的 值计算和副作用,是不确定地排序的 相对于任何其他参数。 [...]
因此
tie
的第二个参数可能是取消引用递增迭代器的结果或原始迭代器。
C++17之前,情况有点复杂:
如果
++
和 *
都调用函数(例如,当 it
的类型是复杂类时),则行为是 未指定,与 C++17 以来的情况类似;否则,行为是未定义。
根据 N4140(C++14 草案)[expr.call]/8:
[ 注: 后缀表达式和后缀表达式的求值 参数彼此之间都是无序的。 所有方面 参数评估的效果在函数之前排序 输入(参见 [intro.execution])。 — 尾注 ]
因此,代码是未定义的行为,因为一个参数的计算与另一个参数没有顺序。 两个参数的评估可能会重叠,从而导致数据竞争。 除非另有说明...
根据 N4140 [执行简介]/15:
调用函数时(无论该函数是否内联),每个 与任何参数相关的值计算和副作用 表达式,或使用指定被调用的后缀表达式 函数,在执行每个表达式或之前排序 被调用函数体中的语句。 [ 注: 值 与不同参数相关的计算和副作用 表达式是无序的。 — 尾注 ] 每一次评价 在调用函数(包括其他函数调用)中不是 在执行之前或之后以其他方式明确排序 被调用函数的主体的顺序不确定 到被调用函数的执行。9 几个 C++ 中的上下文会导致函数调用的求值,即使没有 相应的函数调用语法出现在翻译单元中。 [ 示例: new 表达式的求值会调用一个或多个分配函数和构造函数;参见[expr.new]。对于另一个 例如,调用转换函数([class.conv.fct])可以 出现在没有出现函数调用语法的上下文中。 — 结束示例] 被调用函数执行的顺序约束(如上所述)是函数的特征 无论调用的表达式的语法如何,都会按求值进行调用 该功能可能是。
9) 换句话说,函数执行不会与每个函数交错执行 其他。
因此,如果运算符实际上是函数调用,则行为同样是未指定的。