这是“清除失败"吗?语言规定? [英] Is this "elision failure" language-mandated?
问题描述
考虑以下代码:
#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 :-) ...)
我希望该功能可以简单实现:
I expect the function to be implemented as simply:
bar():
mov eax, 123
ret
,但是该实现调用operator new()
,用我的文字构造一个std::string
,然后调用operator delete()
.至少-gcc 9和clang 9就是这样做的( GodBolt ).这是clang输出:
but instead, the implementation calls operator new()
, constructs an std::string
with my literal, then calls operator delete()
. At least - that's what gcc 9 and clang 9 do (GodBolt). Here's the clang output:
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()
内部的所有情况.为什么不消除"/优化字符串?更具体地说:
My question is: Clearly, the compiler has full knowledge of everything going on inside bar()
. Why is it not "eliding"/optimizing the string away? More specifically:
- 在基本级别上,在
new()
和delete()
之间有代码,编译器知道该AAFICT不会产生有用的结果. - 其次,
new()
和delete()
会自行调用.毕竟,标准AFAIK允许进行小字符串优化,因此即使clang/gcc尚未选择使用它,它也可以使用.意味着实际上并不需要在此调用new()
或delete()
.
- At the basic level there's the code between then
new()
anddelete()
, which AFAICT the compiler knows results in nothing useful. - Secondarily, the
new()
anddelete()
calls themselves. After all, small-string-optimization is allowed by the standard AFAIK, so even though clang/gcc hasn't chosen to use that - it could have; meaning that it's not actually required to callnew()
ordelete()
there.
我特别感兴趣的是其中的哪一部分直接归因于语言标准,以及哪一部分是编译器非最佳性.
I'm particularly interested in what part of this is directly due to the language standard, and what part is compiler non-optimality.
推荐答案
您的代码中没有任何内容代表省略",因为该术语通常在C ++上下文中使用.不允许编译器以删除"为理由从该代码中删除任何内容.
Nothing in your code represents "elision" as that term is commonly used in a C++ context. The compiler is not permitted to remove anything from that code on the grounds of "elision".
编译器删除该字符串的唯一依据是基于好像"规则.也就是说,字符串创建/销毁的行为是否对用户可见,因此无法删除?
The only grounds a compiler has to remove the creation of that string is on the basis of the "as if" rule. That is, is the behavior of the string creation/destruction visible to the user and therefore not able to be removed?
由于它使用std::allocator
和标准字符特征,因此basic_string
构造和销毁本身不会被用户覆盖.因此,存在这样的观点,即字符串的创建不是函数调用的可见副作用,因此可以根据好像"规则将其删除.
Since it uses std::allocator
and the standard character traits, the basic_string
construction and destruction itself is not being overridden by the user. So there is some basis for the idea that the string's creation is not a visible side-effect of the function call and thus could be removed under the "as if" rule.
但是,由于指定了std::allocator::allocate
来调用::operator new
,并且operator new
是全局可替换的,因此有理由认为这是构造这种字符串的明显副作用.因此,编译器无法按照好像"规则将其删除.
However, because std::allocator::allocate
is specified to call ::operator new
, and operator new
is globally replaceable, it is reasonable to argue that this is a visible side effect of the construction of such a string. And therefore, the compiler cannot remove it under the "as if" rule.
如果编译器知道您尚未替换operator new
,则它理论上可以优化字符串.
If the compiler knows that you have not replaced operator new
, then it can in theory optimize the string away.
这并不意味着任何特定的编译器 都会这样做.
That doesn't mean that any particular compiler will do so.
这篇关于这是“清除失败"吗?语言规定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!