此省略失败语言是强制性的吗?

问题描述 投票:2回答:1

请考虑以下代码:

#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!"

我的问题是:显然,编译器将所有内容放在“它的前面”,以查看发生了什么。为什么不将字符串消除掉?更具体地说:

  1. [在基本级别上,然后是new()delete()之间的代码,编译器知道该AFAICT不会产生有用的结果。
  2. 其次,new()delete()会自称。毕竟,标准AFAIK允许进行小字符串优化,因此即使clang / gcc尚未选择使用它,它也[[could可以使用;表示实际上并不需要在此处调用new()delete()
我对其中的哪一部分直接归因于语言标准,以及哪一部分是编译器非最佳性特别感兴趣。
c++ language-lawyer compiler-optimization stdstring elision
1个回答
0
投票
您的代码中没有任何内容代表"elision" as that term is commonly used in a C++ context。不允许编译器以“省略”为理由从该代码中删除任何内容。

编译器必须删除该字符串的唯一依据是基于“好像”规则。也就是说,字符串创建/销毁的行为对用户是否可见,因此无法删除?

由于使用std::allocator和标准字符特征,因此basic_string的构造和销毁本身不会被用户覆盖。因此,存在这样的想法,即字符串的创建不是函数调用的可见副作用,因此可以根据“好像”规则将其删除。

但是,由于指定了std::allocator::allocate来调用::operator new,并且operator new是全局可替换的,因此有理由认为这是构造这种字符串的明显副作用。因此,编译器无法按照“好像”规则将其删除。

如果编译器知道您尚未替换operator new,则理论上它可以将字符串优化掉。

这并不意味着任何特定的编译器

将都会这样做。

© www.soinside.com 2019 - 2024. All rights reserved.