I was playing with www.godbolt.org to check what code generates better assembly code, and I can't understand why this two different approaches generate different results (in assembly commands).
The first approach is to declare a string, and then later set a value:
#include <string>
int foo() {
    std::string a;
    a = "abcdef";
    return a.size();
}
Which, in my gcc 7.4 (-O3) outputs:
.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
So, I imagined that if I initialize the string in the declaration, the output assembly would be shorter:
int bar() {
    std::string a {"abcdef"};
    return a.size();
}
And indeed it is:
bar():
        mov     eax, 6
        ret
Why this huge difference? What prevents gcc to optimize the first version similar to the second?
godbolt link
This is just a guess:
operator= has a strong exception guarantee; which means:
If an exception is thrown for any reason, this function has no effect (strong exception guarantee). (since C++11)
(source)
So while the constructor can leave the object in any condition it likes, operator= needs to make sure that the object is the same as before; I suspect that's why the call to operator delete is there (to clean up potentially allocated memory).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With