C++ std::string 初始化性能更好(汇编)

Edu*_*des 6 c++ optimization

我在玩 www.godbolt.org 来检查哪些代码会生成更好的汇编代码,但我不明白为什么这两种不同的方法会生成不同的结果(在汇编命令中)。

第一种方法是声明一个字符串,然后再设置一个值:

#include <string>
int foo() {
    std::string a;
    a = "abcdef";
    return a.size();
}
Run Code Online (Sandbox Code Playgroud)

其中,在我的 gcc 7.4 ( -O3) 输出中:

.LC0:
        .string "abcdef"
foo():
        push    rbp
        mov     r8d, 6
        mov     ecx, OFFSET FLAT:.LC0
        xor     edx, edx
        push    rbx
        xor     esi, esi
        sub     rsp, 40
        lea     rbx, [rsp+16]
        mov     rdi, rsp
        mov     BYTE PTR [rsp+16], 0
        mov     QWORD PTR [rsp], rbx
        mov     QWORD PTR [rsp+8], 0
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_replace(unsigned long, unsigned long, char const*, unsigned long)
        mov     rdi, QWORD PTR [rsp]
        mov     rbp, QWORD PTR [rsp+8]
        cmp     rdi, rbx
        je      .L1
        call    operator delete(void*)
.L1:
        add     rsp, 40
        mov     eax, ebp
        pop     rbx
        pop     rbp
        ret
        mov     rbp, rax
        jmp     .L3
foo() [clone .cold]:
.L3:
        mov     rdi, QWORD PTR [rsp]
        cmp     rdi, rbx
        je      .L4
        call    operator delete(void*)
.L4:
        mov     rdi, rbp
        call    _Unwind_Resume
Run Code Online (Sandbox Code Playgroud)

所以,我想象如果我在声明中初始化字符串,输出程序集会更短:

int bar() {
    std::string a {"abcdef"};
    return a.size();
}
Run Code Online (Sandbox Code Playgroud)

确实是这样:

bar():
        mov     eax, 6
        ret
Run Code Online (Sandbox Code Playgroud)

为什么会有如此巨大的差异?是什么阻止 gcc 优化类似于第二个版本的第一个版本?

神箭链接

Dan*_*our 4

这只是一个猜测:

operator=具有强有力的异常保障;意思是:

如果由于任何原因抛出异常,则该函数不起作用(强异常保证)。(自 C++11 起)

(来源)

因此,虽然构造函数可以让对象处于它喜欢的任何状态,operator=但需要确保该对象与以前相同;我怀疑这就是为什么调用操作符删除(以清理可能分配的内存)的原因。