“as-if rule”赋予编译器优化或重新排序表达式的权利,这些表达式在某些规则下不会对程序的输出和正确性产生影响,例如:
§1.9.5
执行格式良好的程序的符合要求的实施方案 产生与可能的执行之一相同的可观察行为 具有相同的抽象机的相应实例的 程序和相同的输入。
我上面链接的cppreference网址特别提到了易失性对象的值的特殊规则,以及C ++ 14下的“新表达式”:
New-expression还有as-if规则的另一个例外:编译器 即使a,也可以删除对可替换分配函数的调用 提供了用户定义的替换,并且具有可观察到的副作用。
我认为这里的“可替换”就是在
中所讨论的内容§18.6.1.1.2
可替换:C ++程序可以使用此函数定义函数 签名取代了C ++定义的默认版本 标准库。
根据as-if规则可以删除或重新排序下面的mem
是否正确?
{
... some conformant code // upper block of code
auto mem = std::make_unique<std::array<double, 5000000>>();
... more conformant code, not using mem // lower block of code
}
有没有办法确保它不被删除,并保持在代码的上下块之间?我想到一个放置良好的volatile(或/或volatile std :: array或auto的左侧),但由于没有mem
的读数,我认为即使这样也无法在 as-if下帮助规则。
旁注;我无法让visual studio 2015优化mem
和分配。
澄清:观察的方法是对OS的分配调用来自两个块的任何i / o。这一点是针对测试用例和/或尝试在新位置分配对象。
答案 0 :(得分:4)
是;不,不在C ++中。
C ++的抽象机器根本不讨论系统分配调用。只有影响抽象机器行为的这种调用的副作用才能被C ++修复,即使这样,编译器也可以自由地做其他的事情,只要它能产生相同的可观察行为。程序在抽象机器中。
在抽象机器中,auto mem = std::make_unique<std::array<double, 5000000>>();
创建变量mem
。如果使用它,则可以访问大量double
个打包到数组中的内容。抽象机器可以自由抛出异常,或者为您提供大量的double
s;要么就好了。
请注意,它是一个合法的C ++编译器,通过new
替换所有分配失败的无条件throw
(或者对于无投掷版本返回nullptr
),但是实施的质量很差。
在分配它的情况下,C ++标准并没有真正说明它的来源。例如,编译器可以自由地使用静态数组,并使delete
调用为无操作(注意它可能必须证明它捕获了在缓冲区上调用delete
的所有方法)。 / p>
接下来,如果你有一个静态数组,如果没有人读或写(并且无法观察到结构),编译器可以自由地消除它。
话虽如此,上面的大部分依赖于编译器知道发生了什么。
因此,一种方法是让编译器无法知道。让你的代码加载一个DLL,然后在你希望知道其状态的点处将指针传递给unique_ptr
到该DLL。
因为编译器无法优化运行时DLL调用,所以变量的状态基本上必须符合您的预期。
可悲的是,没有标准的方法来动态加载C ++中的代码,因此您必须依赖于当前的系统。
所述DLL可以单独写成noop;或者,甚至,您可以检查一些外部状态,并根据外部状态有条件地加载并将数据传递给DLL。只要编译器无法证明所说的外部状态会发生,它就无法围绕调用而不是进行优化。然后,永远不要设置那个外部状态。
将变量声明在块的顶部。在未初始化时将指针传递给伪外部DLL。在初始化之前重复,之后重复。最后,在块中结束之前执行它,然后再将其.reset()
,然后再重新执行。