gpt4 book ai didi

c++ - 原始 new[]/delete[] 与 std::vector 的优化

转载 作者:可可西里 更新时间:2023-11-01 15:08:54 26 4
gpt4 key购买 nike

让我们摆弄一下非常基本的动态分配内存。我们取一个 3 的 vector ,设置它的元素并返回 vector 的总和。

在第一个测试用例中,我使用了原始指针 new[]/delete[] .在第二个中我使用了 std::vector :

#include <vector>   

int main()
{
//int *v = new int[3]; // (1)
auto v = std::vector<int>(3); // (2)


for (int i = 0; i < 3; ++i)
v[i] = i + 1;

int s = 0;
for (int i = 0; i < 3; ++i)
s += v[i];

//delete[] v; // (1)
return s;
}

(1) ( new[]/delete[] ) 的组装

main:                                   # @main
mov eax, 6
ret

(2) ( std::vector ) 的组装

main:                                   # @main
push rax
mov edi, 12
call operator new(unsigned long)
mov qword ptr [rax], 0
movabs rcx, 8589934593
mov qword ptr [rax], rcx
mov dword ptr [rax + 8], 3
test rax, rax
je .LBB0_2
mov rdi, rax
call operator delete(void*)
.LBB0_2: # %std::vector<int, std::allocator<int> >::~vector() [clone .exit]
mov eax, 6
pop rdx
ret

两个输出都取自 https://gcc.godbolt.org/-std=c++14 -O3

在这两个版本中,返回值都是在编译时计算的,所以我们只看到 mov eax, 6; ret .

用原始的new[]/delete[]动态分配被完全删除。与 std::vector然而,内存被分配、设置和释放。

这种情况即使使用未使用的变量 auto v = std::vector<int>(3) : 调用 new ,设置内存然后调用delete .

我意识到这很可能是一个几乎不可能给出的答案,但也许有人有一些见解并且可能会弹出一些有趣的答案。

不允许编译器优化删除 std::vector 中的内存分配的促成因素是什么?情况,就像原始内存分配情况一样?

最佳答案

当使用指向动态分配数组的指针时(直接使用 new[] 和 delete[]),编译器优化了对 operator newoperator delete 的调用即使它们有明显的副作用。 C++ 标准第 5.3.4 节第 10 段允许此优化:

An implementation is allowed to omit a call to a replaceable global allocation function (18.6.1.1, 18.6.1.2). When it does so, the storage is instead provided by the implementation or...

我会在最后展示句子的其余部分,这很重要。

这种优化相对较新,因为它首先在 C++14 中被允许(提案 N3664)。 Clang supported it since 3.4 .最新版本的 gcc,即 5.3.0,没有利用这种放宽的 as-if 规则。它产生以下代码:

main:
sub rsp, 8
mov edi, 12
call operator new[](unsigned long)
mov DWORD PTR [rax], 1
mov DWORD PTR [rax+4], 2
mov rdi, rax
mov DWORD PTR [rax+8], 3
call operator delete[](void*)
mov eax, 6
add rsp, 8
ret

MSVC 2013 也不支持这种优化。它产生以下代码:

main:
sub rsp,28h
mov ecx,0Ch
call operator new[] ()
mov rcx,rax
mov dword ptr [rax],1
mov dword ptr [rax+4],2
mov dword ptr [rax+8],3
call operator delete[] ()
mov eax,6
add rsp,28h
ret

我目前无法访问 MSVC 2015 Update 1,因此我不知道它是否支持此优化。

最后是icc 13.0.1生成的汇编代码:

main:
push rbp
mov rbp, rsp
and rsp, -128
sub rsp, 128
mov edi, 3
call __intel_new_proc_init
stmxcsr DWORD PTR [rsp]
mov edi, 12
or DWORD PTR [rsp], 32832
ldmxcsr DWORD PTR [rsp]
call operator new[](unsigned long)
mov rdi, rax
mov DWORD PTR [rax], 1
mov DWORD PTR [4+rax], 2
mov DWORD PTR [8+rax], 3
call operator delete[](void*)
mov eax, 6
mov rsp, rbp
pop rbp
ret

显然,它不支持这种优化。我无法访问最新版本的 icc,即 16.0。

所有这些代码片段都是在启用优化的情况下生成的。

当使用 std::vector 时,所有这些编译器都没有优化分配。当编译器不执行优化时,要么是因为某种原因它不能执行,要么就是还不受支持。

What are the contributing factors that don't allow compiler optimizations to remove the memory allocation in the std::vector case, like in the raw memory allocation case?

编译器没有执行优化,因为不允许这样做。为了看清这一点,让我们看看 5.3.4 中第 10 段的其余句子:

An implementation is allowed to omit a call to a replaceable global allocation function (18.6.1.1, 18.6.1.2). When it does so, the storage is instead provided by the implementation or provided by extending the allocation of another new-expression.

这意味着您可以忽略对可替换全局分配函数的调用,前提是它源自 new 表达式。在同一节的第 1 段中定义了一个新表达式。

下面的表达式

new int[3]

是一个新表达式,因此允许编译器优化关联的分配函数调用。

另一方面,下面的表达式:

::operator new(12)

不是新表达式(参见 5.3.4 第 1 段)。这只是一个函数调用表达式。换句话说,这被视为典型的函数调用。此函数无法优化掉,因为它是从另一个共享库导入的(即使您静态链接运行时,函数本身也会调用另一个导入的函数)。

std::vector 使用的默认分配器使用 ::operator new 分配内存,因此不允许编译器优化它。

让我们测试一下。这是代码:

int main()
{
int *v = (int*)::operator new(12);

for (int i = 0; i < 3; ++i)
v[i] = i + 1;

int s = 0;
for (int i = 0; i < 3; ++i)
s += v[i];

delete v;
return s;
}

使用Clang 3.7编译得到如下汇编代码:

main:                                   # @main
push rax
mov edi, 12
call operator new(unsigned long)
movabs rcx, 8589934593
mov qword ptr [rax], rcx
mov dword ptr [rax + 8], 3
test rax, rax
je .LBB0_2
mov rdi, rax
call operator delete(void*)
.LBB0_2:
mov eax, 6
pop rdx
ret

这与使用 std::vector 时生成的汇编代码完全相同,除了 mov qword ptr [rax], 0 来自 std 的构造函数: :vector(编译器应该删除它但由于其优化算法存在缺陷而未能这样做)。

关于c++ - 原始 new[]/delete[] 与 std::vector 的优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34590885/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com