我想知道在什么情况下,像GCC和LLVM这样的编译器能够将同一函数中的多个调用优化到一些简单的成员函数,例如STL容器的size()
和length()
到一个调用
例如,如果我在同一个函数中将值与容器的大小进行两次比较,但实际上从未真正更改容器,那么它是否可以将它们组合成一个函数调用,如果是,那么何时?
编译器应该能够进行优化,除非它可能认为另一个线程可能同时混淆容器。另一方面,循环中典型的it != x.end()
保护似乎只针对x.end()
的一次调用进行了优化,我认为这种情况会发生,因为如果其他一些线程会添加/删除来自{{1}的内容然后它会使迭代器x
无效,所以我们可以自由地进行优化,因为无论如何我们都会有未定义的行为。
答案 0 :(得分:1)
允许编译器省略没有可见效果的代码。参考:C ++ 11规范草案4296在1.9程序执行[intro.execution]§5
中说...贴合 如下所述,实现需要模拟(仅)抽象机器的可观察行为 下方。
注释给出了以下精度(强调我的):
此规定有时被称为“as-if”规则,因为实施可以自由地忽略对此的任何要求 国际标准,只要结果就好像已经遵守了要求,只要可以从中确定 程序的可观察行为。例如,如果可以的话,实际的实现不需要评估表达式的一部分 推断出它的值没有被使用,并且没有副作用影响程序的可观察行为。
如果编译器知道某个特定方法没有副作用,它可以替换(提供x
不易变):
int x = myfunction(y);
... // other instructions not changing x
int x = myfunction(z);
与
int x = myfunction(z);
... // other instructions not changing x
这里的问题是你从标准库调用一个函数,编译器可能不知道实现是否有副作用。例如,调试实现可以通过调用header(*)中不存在的方法来跟踪对size
方法的所有调用,但这是禁止在此处省略代码的唯一原因。
更改容器的其他线程是不是编译器的问题,而是程序员的问题。 您必须同步访问权限。
(*)如注释中所述,容器代码仅在头文件中(模板通用)编译器在编译时可以知道size
方法没有可见的副作用并且可以优化第二个电话。但这不是标准所要求的,应视为实施细节。