假设规则和移除分配
as-if rule and removal of allocation
“as-if rule”赋予编译器优化或重新排序表达式的权利,这些表达式在某些规则下不会对程序的输出和正确性产生影响,例如;
§1.9.5
A conforming implementation executing a well-formed program shall
produce the same observable behavior as one of the possible executions
of the corresponding instance of the abstract machine with the same
program and the same input.
我上面链接的 cppreference url 特别提到了 volatile 对象值的特殊规则,以及 C++14 下的 "new expressions":
New-expression has another exception from the as-if rule: the compiler
may remove calls to the replaceable allocation functions even if a
user-defined replacement is provided and has observable side-effects.
我假设 "replaceable" 这就是
中的例子
§18.6.1.1.2
Replaceable: a C++ program may define a function with this function
signature that displaces the default version defined by the C++
standard library.
下面的 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(either/or volatile std::array 或 auto 的左侧),但由于没有读取 mem
,我认为即使这样在 [=32 下也无济于事=]如同规则。
旁注;我一直无法获得 visual studio 2015 来优化 mem
和分配。
澄清:观察的方式是对OS的分配调用来自两个块的任何i/o。这一点是针对测试用例 and/or 试图让对象分配到新位置。
是;不。不在 C++ 中。
C++的抽象机根本不谈系统分配调用。只有影响抽象机行为的这种调用的副作用由 C++ 修复,即使这样编译器也可以自由地做其他事情,所以只要 as-if 它会导致部分相同的可观察行为抽象机中的程序。
在抽象机中,auto mem = std::make_unique<std::array<double, 5000000>>();
创建了一个变量mem
。如果使用它,您可以访问打包到数组中的大量 double
。抽象机可以随意抛出异常,或者给你提供那么大量的double
;哪个都可以。
请注意,这是一个合法的 C++ 编译器,它通过 new
将所有分配替换为无条件的 throw
分配失败(或返回 nullptr
用于无抛出版本),但那将是一个糟糕的实施质量。
在分配它的情况下,C++ 标准并没有真正说明它来自哪里。例如,编译器可以自由使用静态数组,并使 delete
调用 no-op(请注意,它可能必须证明它捕获了在缓冲区上调用 delete
的所有方法) .
接下来,如果你有一个静态数组,如果没有人读取或写入它(并且无法观察到构造),编译器可以随意删除它。
话虽这么说,上面的大部分内容都依赖于编译器知道发生了什么。
所以一个办法就是让编译器无法知道。让您的代码加载一个 DLL,然后将指向 unique_ptr
的指针传递给该 DLL,在您希望知道其状态的位置。
因为编译器无法优化 run-time DLL 调用,变量的状态基本上必须是您期望的状态。
遗憾的是,在 C++ 中没有动态加载代码的标准方法,因此您将不得不依赖您当前的系统。
上述DLL可以单独写成noop;或者,您甚至可以检查一些外部状态,并根据外部状态有条件地加载数据并将其传递给 DLL。只要编译器不能证明所说的外部状态会发生,它就不能围绕正在进行的调用 not 进行优化。然后,永远不要设置外部状态。
在块的顶部声明变量。在未初始化时将指向它的指针传递给 fake-external-DLL。在初始化之前重复,然后在之后重复。然后最后,在销毁它之前在块的末尾执行它,.reset()
它,然后再执行一次。
“as-if rule”赋予编译器优化或重新排序表达式的权利,这些表达式在某些规则下不会对程序的输出和正确性产生影响,例如;
§1.9.5
A conforming implementation executing a well-formed program shall produce the same observable behavior as one of the possible executions of the corresponding instance of the abstract machine with the same program and the same input.
我上面链接的 cppreference url 特别提到了 volatile 对象值的特殊规则,以及 C++14 下的 "new expressions":
New-expression has another exception from the as-if rule: the compiler may remove calls to the replaceable allocation functions even if a user-defined replacement is provided and has observable side-effects.
我假设 "replaceable" 这就是
中的例子§18.6.1.1.2
Replaceable: a C++ program may define a function with this function signature that displaces the default version defined by the C++ standard library.
下面的 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(either/or volatile std::array 或 auto 的左侧),但由于没有读取 mem
,我认为即使这样在 [=32 下也无济于事=]如同规则。
旁注;我一直无法获得 visual studio 2015 来优化 mem
和分配。
澄清:观察的方式是对OS的分配调用来自两个块的任何i/o。这一点是针对测试用例 and/or 试图让对象分配到新位置。
是;不。不在 C++ 中。
C++的抽象机根本不谈系统分配调用。只有影响抽象机行为的这种调用的副作用由 C++ 修复,即使这样编译器也可以自由地做其他事情,所以只要 as-if 它会导致部分相同的可观察行为抽象机中的程序。
在抽象机中,auto mem = std::make_unique<std::array<double, 5000000>>();
创建了一个变量mem
。如果使用它,您可以访问打包到数组中的大量 double
。抽象机可以随意抛出异常,或者给你提供那么大量的double
;哪个都可以。
请注意,这是一个合法的 C++ 编译器,它通过 new
将所有分配替换为无条件的 throw
分配失败(或返回 nullptr
用于无抛出版本),但那将是一个糟糕的实施质量。
在分配它的情况下,C++ 标准并没有真正说明它来自哪里。例如,编译器可以自由使用静态数组,并使 delete
调用 no-op(请注意,它可能必须证明它捕获了在缓冲区上调用 delete
的所有方法) .
接下来,如果你有一个静态数组,如果没有人读取或写入它(并且无法观察到构造),编译器可以随意删除它。
话虽这么说,上面的大部分内容都依赖于编译器知道发生了什么。
所以一个办法就是让编译器无法知道。让您的代码加载一个 DLL,然后将指向 unique_ptr
的指针传递给该 DLL,在您希望知道其状态的位置。
因为编译器无法优化 run-time DLL 调用,变量的状态基本上必须是您期望的状态。
遗憾的是,在 C++ 中没有动态加载代码的标准方法,因此您将不得不依赖您当前的系统。
上述DLL可以单独写成noop;或者,您甚至可以检查一些外部状态,并根据外部状态有条件地加载数据并将其传递给 DLL。只要编译器不能证明所说的外部状态会发生,它就不能围绕正在进行的调用 not 进行优化。然后,永远不要设置外部状态。
在块的顶部声明变量。在未初始化时将指向它的指针传递给 fake-external-DLL。在初始化之前重复,然后在之后重复。然后最后,在销毁它之前在块的末尾执行它,.reset()
它,然后再执行一次。