考虑以下代码:
#include <utility>
#include <string>
int bar() {
std::pair<int, std::string> p {
123, "Hey... no small-string optimization for me please!" };
return p.first;
}
我期望这个函数的实现应该尽可能地简单:
bar():
mov eax, 123
ret
但是实现调用的是 operator new()
, 使用我的字面量构造一个 std::string
, 然后调用 operator delete()
. 至少 - 这是 gcc 9 和 clang 9 的做法 (GodBolt). 这是 clang 输出的结果:
bar(): # @bar()
push rbx
sub rsp, 48
mov dword ptr [rsp + 8], 123
lea rax, [rsp + 32]
mov qword ptr [rsp + 16], rax
mov edi, 51
call operator new(unsigned long)
mov qword ptr [rsp + 16], rax
mov qword ptr [rsp + 32], 50
movups xmm0, xmmword ptr [rip + .L.str]
movups xmmword ptr [rax], xmm0
movups xmm0, xmmword ptr [rip + .L.str+16]
movups xmmword ptr [rax + 16], xmm0
movups xmm0, xmmword ptr [rip + .L.str+32]
movups xmmword ptr [rax + 32], xmm0
mov word ptr [rax + 48], 8549
mov qword ptr [rsp + 24], 50
mov byte ptr [rax + 50], 0
mov ebx, dword ptr [rsp + 8]
mov rdi, rax
call operator delete(void*)
mov eax, ebx
add rsp, 48
pop rbx
ret
.L.str:
.asciz "Hey... no small-string optimization for me please!"
我的问题是:编译器显然对
bar()
内部发生的一切都有充分的了解。为什么它不会 "省略"/优化字符串?更具体地说:
- 基本上是在
new()
和delete()
之间的代码,我认为编译器知道这些代码没有任何有用的结果。 - 其次,
new()
和delete()
的调用本身。毕竟,标准允许使用小字符串优化(SSO),所以即使clang/gcc没有选择使用它,但它 可以 使用;这意味着在那里并不真正需要调用new()
或delete()
。
foo()
和因此为bar()
允许不同的可观察行为。delete new int;
中也存在问题。您可以通过使用-fno-delete-null-pointer-checks
标志来抑制该优化并解决此问题。 - Jarod42