c++ - 是否允许编译器优化堆内存分配?

标签 c++ gcc optimization clang language-lawyer

考虑以下使用 new 的简单代码(我知道没有 delete[],但它不属于这个问题):

int main()
{
    int* mem = new int[100];

    return 0;
}

是否允许编译器优化 new 调用?

在我的研究中,g++ (5.2.0)和 Visual Studio 2015 不优化 new 调用,while clang (3.0+) does .所有测试都是在启用完全优化的情况下进行的(-O3 用于 g++ 和 clang,用于 Visual Studio 的 Release模式)。

new 不是在幕后进行系统调用,使得编译器不可能(并且非法)对其进行优化吗?

编辑:我现在已经从程序中排除了未定义的行为:

#include <new>  

int main()
{
    int* mem = new (std::nothrow) int[100];
    return 0;
}

clang 3.0 does not optimize that out不再,但是 later versions do .

EDIT2:

#include <new>  

int main()
{
    int* mem = new (std::nothrow) int[1000];

    if (mem != 0)
      return 1;

    return 0;
}

clang always returns 1 .

最佳答案

历史似乎是 clang 遵循 N3664: Clarifying Memory Allocation 中规定的规则这允许编译器围绕内存分配进行优化,但作为 Nick Lewycky points out :

Shafik pointed out that seems to violate causality but N3664 started life as N3433, and I'm pretty sure we wrote the optimization first and wrote the paper afterwards anyway.

因此 clang 实现了优化,后来成为作为 C++14 的一部分实现的提案。

基本问题是这是否是 N3664 之前的有效优化,这是一个棘手的问题。我们将不得不去 as-if rule C++ 标准草案 1.9 Program execution 中包含(强调我的):

The semantic descriptions in this International Standard define a parameterized nondeterministic abstract machine. This International Standard places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.5

注释 5 说:

This provision is sometimes called the “as-if” rule, because an implementation is free to disregard any requirement of this International Standard as long as the result is as if the requirement had been obeyed, as far as can be determined from the observable behavior of the program. For instance, an actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no side effects affecting the observable behavior of the program are produced.

因为 new 可以抛出一个具有可观察行为的异常,因为它会改变程序的返回值,这似乎反对它被 as-if 规则允许

尽管可以争论何时抛出异常是实现细节,因此即使在这种情况下 clang 也可以决定它不会导致异常,因此省略 new 调用不会违反好像规则

as-if 规则下,优化对非抛出版本的调用似乎也是有效的。

但是我们可以在不同的翻译单元中有一个替换的全局运算符 new,这可能会导致这影响可观察到的行为,因此编译器必须有某种方式来证明情况并非如此,否则它将无法在不违反假设规则 的情况下执行此优化。以前版本的 clang 在这种情况下确实优化为 this godbolt example shows这是通过 Casey here 提供的,使用这段代码:

#include <cstddef>

extern void* operator new(std::size_t n);

template<typename T>
T* create() { return new T(); }

int main() {
    auto result = 0;
    for (auto i = 0; i < 1000000; ++i) {
        result += (create<int>() != nullptr);
    }

    return result;
}

并将其优化为:

main:                                   # @main
    movl    $1000000, %eax          # imm = 0xF4240
    ret

这确实看起来太激进了,但后来的版本似乎没有这样做。

关于c++ - 是否允许编译器优化堆内存分配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58392330/

相关文章:

c++ - 将 vector 放置到 map 中

c++ - 这是将 csv 文件导入 MS Access 的正确 SQL 语法吗?

c - 未声明的 WinApi Commctrl 轨迹栏标识符

javascript - for 循环与 if 条件

r - 在R中快速生成数字序列的方法

C++ 卡夫卡客户端 (rdkafka)

c++ - 虚函数关键字

c++ - gcc 会根据条件优化我的循环吗?

c - 如何在 mingw 上使用 libcurl 和 gcc 编译应用程序

algorithm - 有界 0-1 多背包的任何伪多项式算法?