为什么这个未使用的variables没有被优化?

我和Godbolt的CompilerExplorer玩过。 我想看看某些优化有多好。 我最低工作的例子是:

#include <vector> int foo() { std::vector<int> v {1, 2, 3, 4, 5}; return v[4]; } 

生成的汇编程序(由clang 5.0.0,-O2 -std = c ++ 14):

 foo(): # @foo() push rax mov edi, 20 call operator new(unsigned long) mov rdi, rax call operator delete(void*) mov eax, 5 pop rcx ret 

正如人们所看到的,铿锵知道答案,但在返回之前做了很多事情。 在我看来,即使vector是创build,因为“运营商新/删除”。

任何人都可以向我解释这里发生了什么,为什么它不只是返回?

由GCC生成的代码(不在这里复制)似乎明确地构造了向量。 有谁知道GCC不能推断出结果?

std::vector<T>是一个相当复杂的类,涉及dynamic分配。 虽然clang++ 有时候可以省略堆分配 ,这是一个相当棘手的优化,你不应该依赖它。 例:

 int foo() { int* p = new int{5}; return *p; } 
 foo(): # @foo() mov eax, 5 ret 

作为一个例子,使用std::array<T> (不会dynamic分配) 产生完全内联的代码 :

 #include <array> int foo() { std::array v{1, 2, 3, 4, 5}; return v[4]; } 
 foo(): # @foo() mov eax, 5 ret 

正如Marc Glisse在其他答案的评论中指出的那样,这是标准在[expr.new]中所说的#10 :

允许实现省略对可replace的全局分配函数([new.delete.single],[new.delete.array])的调用。 当这样做的时候,存储是由实现提供的,或者是通过扩展另一个新expression式的分配来提供的。 这个实现可以扩展一个新的expression式e1的分配,为下一个新的expression式e2提供存储,如果分配不被扩展,

正如注释注释, operator new可以被replace。 这可能发生在任何翻译部门。 因此,对于未更换的情况优化程序需要全程序分析。 如果它replace,你必须要调用它当然。

缺省operator new是否是库I / O调用是未指定的。 这很重要,因为库I / O调用是可观察的,因此它们也不能被优化。

N3664改为[expr.new],在一个答案和一个评论中引用,允许newexpression式不调用可replace的全局分配函数。 但是, vector使用std::allocator<T>::allocate分配内存,它直接调用::operator new ,而不是通过newexpression式 。 因此,特殊权限不适用,一般来说编译器不能忽略这样的直接调用::operator new

所有的希望不会丢失,但是,对于std::allocator<T>::allocate的规范有这样的说法:

备注:通过调用​::​operator new获得存储空间,但未指定调用此函数的时间或频率。

利用这个权限,libc ++的std::allocator 使用特殊的clang内build函数向编译器指明elision是允许的。 使用-stdlib=libc++ , clang将您的代码编译为

 foo(): # @foo() mov eax, 5 ret