as-if规则和删除分配

时间:2016-01-20 18:40:08

标签: c++ c++14 as-if

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。这一点是针对测试用例和/或尝试在新位置分配对象。

1 个答案:

答案 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(),然后再重新执行。