在f(x)中,可以在f之前评估x吗?

Pup*_*ppy 52 c++ c++11

我有一个C++程序.这个程序做了这样的事情:

struct MyT {void memfunc(std::unique_ptr<MyT> arg);};
std::unique_ptr<MyT> obj = /* some init */;
obj->memfunc(std::move(obj));
Run Code Online (Sandbox Code Playgroud)

这保证是有效的,还是我最终可以调用成员函数nullptr
标准报价适用.
我知道参数的评估顺序是不合理的,但我不记得调用函数对象的顺序是什么.

Ded*_*tor 19

前C++ 17,它是未定义的行为:

这里引用证明在调用函数和相关副作用之前所有必要的评估都在函数调用之前排序.
此外,所有其他未经特异性测序的评估都是不确定的.
这并没有对评估虽然相对于对方,他们仍然是子表达式任何排序约束未测序相对于对方.

1.9计划执行§15

除非另有说明, 否则对单个运算符的操作数和单个表达式的子表达式的评估是不确定的.
[...]
在运算符结果的值计算之前,对运算符的操作数的值计算进行排序.如果对标量对象的副作用相对于对同一标量对象的其他影响或使用相同标量对象的值进行的值计算未进行排序,则行为未定义.
当调用函数时(无论函数是否为内联函数),与任何参数表达式相关联的每个值计算和副作用,或者使用指定被调用函数的后缀表达式,都会在执行每个表达式或语句之前对其进行排序.叫功能.
[注意:与不同参数表达式相关的值计算和副作用未被排序.-end note]
调用函数(包括其他函数调用)中的每个评估在执行被调用函数体之前或之后没有特别排序,对于被调用函数的执行是不确定的顺序 .9 几个上下文在C++中导致函数调用的评估,即使在翻译单元中没有出现相应的函数调用语法.[...]
对被调用函数的执行的排序约束(如上所述)是被评估的函数调用的特征,无论调用函数的表达式的语法如何.

其他相关的报价是关于 std::move

template typename remove_reference :: type && move(T && t)noexcept;
返回:static_cast <typename remove_reference :: type &&>(t).

而且std::unique_ptr<T>.operator->():

20.7.1.2.4 unique_ptr观察者

指针运算符 - >()const noexcept;
需要:get()!= nullptr.
返回:get().

memfunc通过值获取其参数,因此我们有3个调用:
a)obj->memfunc b)std::move(obj)
c)传递参数的移动构造函数.
因为b)没有改变任何东西,我们可以忽略它的论点:

a和c是不确定的顺序,所以要么可以在另一个之前.
如果首先发生,一切都很好,改变obj无关紧要.
如果c首先发生,则a被评估为零obj,违反前提条件,因此我们有UB.

总之,它是Undefined Behavior,因为其中一个允许的订单具有未定义的行为.

后C++ 17,它定义明确:

8.2.2函数调用[expr.call]

1函数调用是一个post fi x表达式,后跟括号,其中包含一个可能为空的逗号分隔的initializer-clause列表,这些子句构成函数的参数.[...]
[...]
5 post fi x- expression表达式列表中的每个表达式和任何默认参数之前排序.[...]
[...]


Bri*_*ian 18

是的,评估x可以在评估之前,之后或期间进行f(它们是未经测试的).

[ 注意:后缀表达式和参数表达式的评估都是相对于彼此的无法排序的.在输入函数之前,对参数表达式评估的所有副作用进行排序(参见1.9).- 结束说明 ]

(C++ 11,§5.2.2/ 8)

  • 这包括构造参数吗? (3认同)