c++ - 这种“省略失败”是语言规定的吗?
问题描述
考虑以下代码:
#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()
构造一个,然后调用. 至少 - 这就是 gcc 9 和 clang 9 所做的()。这是铿锵声输出:std::string
operator delete()
GodBolt
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()
。为什么它不“删除”/优化字符串?进一步来说:
- 在基本级别上, then
new()
和之间有代码delete()
,编译器知道 AFAICT 不会产生任何有用的结果。 - 其次,
new()
anddelete()
调用自己。毕竟,标准 AFAIK 允许小字符串优化,所以即使 clang/gcc 没有选择使用它 - 它也可以;这意味着实际上不需要打电话new()
或打电话delete()
。
我特别感兴趣的是,这其中的哪一部分直接归因于语言标准,哪一部分是编译器的非最优性。
解决方案
在此处的各种答案和评论中进行了讨论之后,我现在针对 GCC 和 LLVM 提交了以下关于此问题的错误:
GCC 错误 94293:[错过优化] new+delete of未删除的未使用的本地字符串
最小测试用例 ( GodBolt):
void foo() { int *p = new int[1]; *p = 42; delete[] p; }
GCC 错误 94294:[错过优化] 填充本地字符串的无用语句未删除
最小测试用例 ( GodBolt):
void foo() { std::string s { "This is not a small string" }; }
LLVM 错误 45287:[错过优化] 未能删除未使用的 libstdc++ std::string。
最小测试用例 ( GodBolt):
void foo() { std::string s { "This is not a small string" }; }
感谢:@JeffGarret、@NicolBolas、@Jarod42、Marc Glisse。
2021 年 8 月更新:使用最新版本的 clang++、g++ 和 libstc++,所有这些最小的测试用例都如预期的那样避开了内存分配。clang++ 对问题中的 OP 程序也有这种行为,但 GCC 仍然分配和解除分配。
推荐阅读
- python - 一种基于python中收敛数值数据估计收敛结果的方法?
- c++ - 乌龟图形:开始新的一行
- css - 我正在使用 Nextjs,对于导航栏,我通过 CDN 链接使用 bootstrap5,无法为导航栏设置服装?
- jenkins - Jenkins Ingress 与 k8s v1.19
- python - Python - 弹性搜索中的余弦相似度查询期间出现非法参数异常
- typescript -
和 React.createElement - ffmpeg - FFmpeg 和 Gstreamer:方法 SETUP 失败:461 不支持的传输
- node.js - Docker 映像无法在 Raspberry Pi 上运行,出现奇怪的节点错误
- docker - 从 gitlab ci 中的容器发送电子邮件
- reactjs - 有条件地将 TableCell 的全部内容变成链接