【发布时间】:2023-03-12 18:00:02
【问题描述】:
考虑以下代码:
#include <utility>
#include <string>
int bar() {
std::pair<int, std::string> p {
123, "Hey... no small-string optimization for me please!" };
return p.first;
}
(感谢@Jarod42 :-) ...)
我希望该功能可以简单地实现:
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()之间,编译器知道 AFAICT 不会导致任何用处。 - 其次,
new()和delete()调用自己。毕竟,标准 AFAIK 允许小字符串优化,所以即使 clang/gcc 没有选择使用它 - 它可以有;这意味着实际上不需要在那里调用new()或delete()。
我特别感兴趣的是,这其中的哪一部分直接归因于语言标准,哪一部分是编译器的非最优性。
【问题讨论】:
-
new/delete不是可观察到的行为吗? (和new可以throw) -
@Jarod42: 1. 我不确定在 C++20 中是否可以使用 constexpr 向量。 2. 即使是 - 如果理论上允许您使用最多 1,000,000 个字符的小字符串优化,这意味着您可以为
foo()和bar()提供不同的可观察行为。 -
根据en.cppreference.com/w/cpp/language/new#Allocation,分配只能从C++14开始省略。
-
inconsistent-behavior-of-compiler-optimization-of-unused-string 显示
delete new int;的编译器问题 -
我会说 SSO 应该是一致的,否则它主要是 ODR 违规。
标签: c++ language-lawyer compiler-optimization stdstring elision