理解“按原样执行程序”的as-if规则

57

我正在尝试理解“as-if”规则。根据cppreference

“as-if”规则
允许进行任何不改变程序可观察行为的代码转换

解释
C++编译器可以对程序进行任何更改,只要以下条件仍然成立:[...]

对我来说,很难理解“解释”部分的第二个提示:

2) 在程序终止时,写入文件的数据与按原样执行程序时完全相同。

我不理解“按原样执行程序”是什么意思。


13
这意味着编译器不允许进行任何会改变输出的优化(RVO除外)。 - Bathsheba
@Aconcagua,你认为在这种情况下,“按照编写的行为”是什么?如果在你的“按照编写的”程序中输出的顺序是未定义的(根据你的描述听起来是这样),那么对于该程序的任何具体编译,输出的顺序都没有要求。 - Max Langhof
它说文件输出是一个可见的副作用,因此不能被优化或更改顺序。 - Richard Critten
3
这是一个不错的演示,展示了“as if”规则能做什么。在我看来,这是理解它的最佳方式。 - Marek R
6
我非常赞同 - 但值得注意的是,有些人发现仅凭几行文字学习困难,而通过视频学习则容易得多 - Martin Bonner supports Monica
显示剩余2条评论
2个回答

143
周一,你的老板走进你的办公室说:“我需要文件A在星期四之前放在我的桌子上,文件B在星期五之前放在我的桌子上。”他首先描述了他想在文件A中得到什么以及他认为你应该如何完成这些工作,然后又描述了他想要在文件B中得到什么。
在老板的心目中,你会先完成文件A中的任务,在星期四把文件放在他的桌子上,然后开始处理文件B并在星期五完成。但是你意识到,更合理的做法是提前开始文件B的工作,甚至早于文件A。没有什么理由让你的老板知道——他只关心在星期四收到A,星期五收到B。你还意识到,他建议的方法可以改进,因此你采取了略微不同的方法来生产所需的信息。
在这个比喻中,老板就是C++代码,你是编译器。编译器可以重新排列操作(以不同的顺序处理文件),只要可观察行为(将文件放在老板的桌子上)相同即可。同样地,编译器可以对保留可观察行为的代码进行任何变换(使用不同于老板描述的方法)。
特别地,“好像程序按原样执行”意味着“好像你按老板的指示精确完成了工作”(即使你做了一些不同的事情)。

15

该规则的一个重要特点是它指定了实现符合的最小要求,但并不意味着这些要求足以满足任何特定应用程序的需求,也不意味着某些应用程序不需要提供更强的保证。假设执行和记录单个测试结果的过程如下:

  1. 进行实验。
  2. 写下测量结果。
  3. 解锁保险柜。
  4. 将测量结果的纸放入保险柜中。
  5. 锁定保险柜。

如果需要进行三个测试,可以按顺序对每个测试执行以上五个步骤,但以下任何一种步骤顺序也可能是可接受的:

  1. 进行实验 #1
  2. 将测量结果写在纸 #1 上
  3. 进行实验 #2
  4. 将测量结果写在纸 #2 上
  5. 进行实验 #3
  6. 将测量结果写在纸 #3 上
  7. 解锁保险柜
  8. 将纸 #1 放入保险柜中
  9. 将纸 #2 放入保险柜中
  10. 将纸 #3 放入保险柜中
  11. 锁定保险柜

或者--为了避免同时跟踪三张纸:

  1. 进行实验 #1
  2. 将测量结果写在纸 #1 上
  3. 解锁保险柜
  4. 将纸 #1 放入保险柜中
  5. 进行实验 #2
  6. 将测量结果写在纸 #2 上
  7. 把第2张纸放到保险柜里
  8. 做第3个实验
  9. 把测量结果写在第3张纸上
  10. 把第3张纸放到保险柜里
  11. 锁好保险柜

如果一切顺利的话,这三种方法都是等效的。然而,如果第二个实验出了问题并破坏了桌子上摆放的任何文件,使用第二种方法会冒失将第一个实验的结果丢失 - 如果按照完全详细的程序操作,则不会发生这种情况。更糟糕的是,如果第三个实验出大问题并破坏了除了 锁好的 以外的所有东西,第三种方法就会有可能丢失保险柜中的所有内容,甚至是与实验无关的内容。

在某些情况下,第二或第三种方法可能是合适的。在其他情况下,则不是。判断这些方法是否合适需要了解实验所带来的风险、保险柜的内容和许多其他因素。

标准的作者无法知道判断哪些应用程序需要什么样的保证所必需的一切信息。相反,他们依赖于各种实现的生产者和用户来认识到什么样的保证将需要安全有效地完成需要完成的任务。


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