- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
让我们摆弄一下非常基本的动态分配内存。我们取一个 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 new
和 operator 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/
我写了这个课: class StaticList { private: int headFree; int headList; int locNe
我目前正在使用 SQL Server Management Studio 2005,我遇到了一些问题,但首先是我的 DB 架构的摘录(重要的): imghack link to the image 我
范围:两个表。创建新顾客时,他们会将一些有关他们的信息存储到第二个表中(这也是使用触发器完成的,它按预期工作)。这是我的表结构和关系的示例。 表 1-> 赞助人 +-----+---------+--
我想知道,在整个程序中,我使用了很多指向 cstrings 的 char* 指针,以及其他指针。我想确保在程序完成后删除所有指针,即使 Visual Studio 和 Code Blocks 都为我做
考虑以下代码: class Foo { Monster* monsters[6]; Foo() { for (int i = 0; i < 6; i++)
关于 this page , 是这么写的 One reason is that the operand of delete need not be an lvalue. Consider: delet
我无法在 DELETE CASCADE ON UPDATE CASCADE 上添加外键约束。 我使用两个简单的表格。 TAB1 有 2 列:ID int(10) unsigned NOT NULL A
你好,有没有办法把它放在一个声明中? DELETE e_worklist where wbs_element = '00000000000000000054TTO'. DELETE e_workli
我有一个表,它是我系统的核心,向我的客户显示的所有结果都存储在那里。它增长得非常快,因此每 3 小时我应该删除早于 X 的记录以提高性能。 仅删除这些记录就足够了,还是应该在删除后运行优化表? 我正在
这个问题在这里已经有了答案: delete vs delete[] operators in C++ (7 个答案) 关闭 9 年前。 做和做有什么区别: int* I = new int[100]
为什么这段代码是错误的?我是否遗漏了有关 delete 和 delete[] 行为的内容? void remove_stopwords(char** strings, int* length) {
当我使用 new [] 申请内存时。最后,我使用 delete 来释放内存(不是 delete[])。会不会造成内存泄漏? 两种类型: 内置类型,如 int、char、double ... 我不确定。
所以在代码审查期间,我的一位同事使用了 double* d = new double[foo]; 然后调用了 delete d。我告诉他们应该将其更改为 delete [] d。他们说编译器不需要基本
范围:两个表。当一个新顾客被创建时,他们将一些关于他们的信息存储到第二个表中(这也是使用触发器完成的,它按预期工作)。这是我的表结构和关系的示例。 表 1-> 赞助人 +-----+---------
C++14 介绍 "sized" versions of operator delete ,即 void operator delete( void* ptr, std::size_t sz ); 和
我正在执行类似的语句 DELETE FROM USER WHERE USER_ID=1; 在 SQLDeveloper 中。 由于用户在许多表中被引用(例如用户有订单、设置等),我们激活了 ON DE
出于某种原因,我找不到我需要的确切答案。我在这里搜索了最后 20 分钟。 我知道这很简单。很简单。但由于某种原因我无法触发触发器.. 我有一个包含两列的表格 dbo.HashTags |__Id_|_
这是我的代码: #include #include #include int main() { setvbuf(stdout, NULL, _IONBF, 0); setvbuf
是否可以在 postgres 中使用单个命令删除所有表中的所有行(不破坏数据库),或者在 postgres 中级联删除? 如果没有,那么我该如何重置我的测试数据库? 最佳答案 is it possib
我想删除一些临时文件的内容,所以我正在开发一个小程序来帮我删除它们。我有这两个代码示例,但我对以下内容感到困惑: 哪个代码示例更好? 第一个示例 code1 删除文件 1 和 2,但第二个示例 cod
我是一名优秀的程序员,十分优秀!