看看这个简单的函数调用:
f(a(), b());根据标准,a()和b()的调用顺序未指定。C++17有一个附加规则,它不允许a()和b()相互交织。据我所知,在C++17之前,没有这样的规则。
现在,看看这个简单的代码:
int v = 0;
int fn() {
int t = v+1;
v = t;
return 0;
}
void foo(int, int) { }
int main() {
foo(fn(), fn());
}使用C++17规则,v在调用foo之后肯定会具有2的值。但是,这让我想知道,前C++17,是同样的保证吗?或者是v最终变成了1?这有什么区别吗,如果不是int t = v+1; v = t;,我们只有v++
发布于 2019-05-24 11:50:49
v必须在C++ (和C)的所有版本中为2。函数fn()必须执行两次,很明显,每次执行它都会增加v。这里没有多线程,没有数据竞争,fn()不可能只部分执行,然后被中断,而fn()的其他调用则继续进行。
发布于 2019-05-24 12:01:31
C++17有一个附加规则,它不允许a()和b()相互交织。据我所知,在C++17之前,没有这样的规则。
这里有一些适用的规则,尽管措辞和一些细节已经变得更加精确。
C++03 intro.execution/8:
一旦函数的执行开始,调用函数的表达式在被调用函数的执行完成之前不会被计算。脚注8:换言之,职能执行不相互交织。
尽管你可能会说,这实际上并没有涉及到文本中调用函数所调用的其他函数,而且脚注也不是正式的规范。
C++11改变了措辞,很大程度上是因为它引入了多线程语义。C++11和C++14 intro.execution/15,重点是:
当调用函数(无论函数是否内联)时,与任何参数表达式或与指定被调用函数的后缀表达式相关联的每个值计算和副作用,在执行被调用函数正文中的每个表达式或语句之前,都会被排序。注意:与不同参数表达式相关联的值计算和副作用是不按顺序排列的。
我认为,这种措辞毫无疑问,至少在大多数情况下是这样。
C++17 intro.execution/18:
当调用函数(无论函数是否内联)时,与任何参数表达式或与指定被调用函数的后缀表达式相关联的每个值计算和副作用,在执行被调用函数正文中的每个表达式或语句之前,都会被排序。对于每一次函数调用F,对于F内发生的每一次求值A和不发生在F内但在同一线程上并作为同一信号处理程序的一部分(如果有的话)的每一次求值B,在B或B之前对A进行排序。 脚注10,换言之,职能执行不相互交织。
这是一个关于单独函数中的所有计算的更为普遍的陈述,而不仅仅是函数调用中的参数。但据我所知,这种更精确的措辞只是澄清了一些可能不明确的情况,但并没有真正改变语义行为。
发布于 2019-05-24 16:31:58
我怀疑我们混淆了两个概念。调用顺序只在c++17中的表达式中固定。函数的两个调用之间的语句交织一直是不允许的,尽管当优化器掌握了您的代码时,只保证了效果。
如果您编写了a() ; b(),那么在b被完全执行之前,a()将完全执行。如果您编写a(), b()或a() && b(),则相同
如果您编写了a() + b(),那么在c++17之前没有保证a()将在b()之前执行,但是有一个保证,无论哪个先执行,都将在执行另一个之前完全完成。
如果编写c(a(), b()),我的理解是,在b()之前执行a()也不能保证,但是可以保证第一个执行的函数(以两者为准)的效果将在第二个函数启动之前完成,当然还保证在a()和b()完成之前不执行c()。
优化者应该遵守该保证的意图,尽管它可能接受a()和b(),甚至c()的语句,并将它们混合在一起,但是运行代码的效果应该与它们按顺序运行一样。-O0代码可以执行a()然后b()和-O3代码做b()然后是a()吗?也许,这会使调试变得相当困难,所以我希望不会。
编译器只需要在最终结果中给出效果,并且在多线程中,另一个线程可以观察连续的代码行的影响,除非使用特定的线程感知结构。
我的理解是,优化器不能允许a()、b()和c()的特定效果在每个函数之间出现无序,尽管在c++17之前,a()和b()的顺序没有很好的定义-- b()的所有效果可能发生在a()的所有效果之前。
https://stackoverflow.com/questions/56291887
复制相似问题