Noa*_*rik 5 c++ optimization performance clang noexcept
我正在尝试在不同的编译器上自己试验代码。我一直在尝试查找在某些函数上禁用异常的优势(通过二进制足迹)并将其与不禁用异常的函数进行比较,实际上我偶然发现了一个奇怪的情况,其中最好有异常比没有。
我一直在使用Matt Godbolt 的 Compiler Explorer进行这些检查,并且在 x86-64 clang 12.0.1 上进行了检查,没有任何标志(在 GCC 上这种奇怪的行为不存在)。
看看这个简单的代码:
auto* allocated_int()
{
return new int{};
}
int main()
{
delete allocated_int();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
非常简单,几乎删除了从函数返回的已分配指针allocated_int()。
正如预期的那样,二进制占用空间也很小:
allocated_int(): # @allocated_int()
push rbp
mov rbp, rsp
mov edi, 4
call operator new(unsigned long)
mov rcx, rax
mov rax, rcx
mov dword ptr [rcx], 0
pop rbp
ret
Run Code Online (Sandbox Code Playgroud)
此外,非常直接。但是当我将noexcept关键字应用于allocated_int()函数时,二进制膨胀。我将在此处应用生成的程序集:
allocated_int(): # @allocated_int()
push rbp
mov rbp, rsp
sub rsp, 16
mov edi, 4
call operator new(unsigned long)
mov rcx, rax
mov qword ptr [rbp - 8], rcx # 8-byte Spill
jmp .LBB0_1
.LBB0_1:
mov rcx, qword ptr [rbp - 8] # 8-byte Reload
mov rax, rcx
mov dword ptr [rcx], 0
add rsp, 16
pop rbp
ret
mov rdi, rax
call __clang_call_terminate
__clang_call_terminate: # @__clang_call_terminate
push rax
call __cxa_begin_catch
call std::terminate()
Run Code Online (Sandbox Code Playgroud)
为什么 clang 为我们做这个额外的代码?除了调用 之外new(),我没有要求任何其他操作,我希望二进制文件能够反映这一点。
谢谢能解释的人!
为什么 clang 为我们做这个额外的代码?
因为函数的行为是不同的。
我没有请求任何其他操作,而是调用了 new()
通过声明 function noexcept,您已请求std::terminate在异常传播出函数时被调用。
allocated_int在第一个程序中永远不会调用std::terminate,而
allocated_int在第二个程序中可能会调用std::terminate。请注意,如果您记得启用优化器,则添加的代码量会少得多。比较非优化的组装大多是徒劳的。
您可以使用非抛出分配来防止:
return new(std::nothrow) int{};
Run Code Online (Sandbox Code Playgroud)
这确实是一个精明的观察,在非抛出函数中执行可能抛出的事情可能会引入一些额外的工作,如果在潜在抛出函数中完成相同的事情,则不需要完成这些工作。
我一直在尝试查找在某些功能上禁用异常的优势
使用非抛出的优势在调用此类函数时可能会实现;不在函数本身内。
| 归档时间: |
|
| 查看次数: |
92 次 |
| 最近记录: |