Max*_*ner 38 c++ gcc clang compiler-optimization
我玩过Godbolt的CompilerExplorer.我想看看某些优化是多么好.我的最低工作范例是:
#include <vector>
int foo() {
std::vector<int> v {1, 2, 3, 4, 5};
return v[4];
}
Run Code Online (Sandbox Code Playgroud)
生成的汇编程序(通过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
Run Code Online (Sandbox Code Playgroud)
可以看出,clang知道答案,但在返回之前会做很多事情.在我看来,即使是矢量也是由于"operator new/delete"而创建的.
任何人都可以向我解释这里发生了什么以及它为什么不回归?
GCC生成的代码(此处未复制)似乎明确构造了向量.有谁知道海湾合作委员会无法推断出结果?
Vit*_*meo 29
std::vector<T>是一个相当复杂的类,涉及动态分配.虽然clang++ 有时能够忽略堆分配,但这是一个相当棘手的优化,你不应该依赖它.例:
int foo() {
int* p = new int{5};
return *p;
}
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)foo(): # @foo() mov eax, 5 ret
例如,使用std::array<T> (不动态分配) 会产生完全内联的代码:
#include <array>
int foo() {
std::array v{1, 2, 3, 4, 5};
return v[4];
}
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)foo(): # @foo() mov eax, 5 ret
正如Marc Glisse在其他答案的评论中指出的那样,这就是标准在[expr.new]#10中所说的:
允许实现省略对可替换全局分配函数的调用([new.delete.single],[new.delete.array]).当它这样做时,存储由实现提供,或者通过扩展另一个新表达式的分配来提供.实现可以扩展新表达式e1的分配,以便为新表达式e2提供存储,如果以下情况属实,则分配未扩展:[...]
如评论所述,operator new可以替换.这可能发生在任何翻译单位.因此,为未被替换的案例优化程序需要全程序分析.如果它被替换,你当然必须调用它.
是否未指定默认值operator new是库I/O调用.这很重要,因为库I/O调用是可观察的,因此它们也无法优化.