这是“清除失败"吗?语言规定? [英] Is this "elision failure" language-mandated?

查看:68
本文介绍了这是“清除失败"吗?语言规定?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

#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:

  1. 在基本级别上,在new()delete()之间有代码,编译器知道该AAFICT不会产生有用的结果.
  2. 其次,new()delete()会自行调用.毕竟,标准AFAIK允许进行小字符串优化,因此即使clang/gcc尚未选择使用它,它也可以使用.意味着实际上并不需要在此调用new()delete().
  1. At the basic level there's the code between then new() and delete(), which AFAICT the compiler knows results in nothing useful.
  2. Secondarily, the new() and delete() 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 call new() or delete() 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆