c++ - 这是 "elision failure"语言强制要求的吗?

标签 c++ language-lawyer compiler-optimization stdstring elision

考虑以下代码:

#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()那里。

  • 我特别感兴趣的是,这其中的哪一部分直接归因于语言标准,哪一部分是编译器的非最优性。

    最佳答案

    您的代码中没有任何内容代表 "elision" as that term is commonly used in a C++ context .不允许编译器以“省略”为由从该代码中删除任何内容。

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

    由于它使用 std::allocator和标准的性格特征,basic_string构造和破坏本身不会被用户覆盖。因此,字符串的创建不是函数调用的可见副作用,因此可以在“好像”规则下删除的想法有一些基础。

    但是,因为 std::allocator::allocate指定调用::operator new , 和 operator new是全局可替换的,因此有理由认为这是构造这种字符串的可见副作用。因此,编译器无法根据“好像”规则将其删除。

    如果编译器知道你没有替换 operator new ,那么理论上可以优化掉字符串。

    这并不意味着任何特定的编译器都会这样做。

    关于c++ - 这是 "elision failure"语言强制要求的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60816079/

    相关文章:

    c++ - 基于整数类型 "signed-ness"的部分模板特化?

    c++ - 面向侵入式数据结构的面向对象设计

    c++ - 调用另一个翻译单元中专门的功能模板

    c - 由唯一类型限定符组成的声明说明符

    c++ - 这段编译良好的荒谬代码是 Clang 和 GCC 中的错误吗?

    编译器优化 : const on non-pointer function arguments in C

    c++ - 以代数方式将度数值限制为 0 <= x < 360

    javascript - 使用 libssh 从消息中提取 SSH 公钥

    c++ - g++ 编译器标志以最小化二进制大小

    c++ - 为什么我不是分支预测的受害者?