https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98840

            Bug ID: 98840
           Summary: Why does baz call the delete operator for moved
                    unique_ptr
           Product: gcc
           Version: 10.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: dmitriy.ovdienko at gmail dot com
  Target Milestone: ---

I'm trying to evaluate the overhead of the `unique_ptr` and I do not understand
why does Gcc execute the destructor of the `unique_ptr` passed by value?

Let's assume we have two examples of code:

C style:

```
#include <memory>

void foo(int* ptr);

void baz(int value)
{
    int* ptr = new int(value);

    try
    {
        foo(ptr);
    }
    catch(...)
    {
        delete ptr;
        throw;
    }
}
```

The asm (/O3):

```
baz(int):
        push    rbp
        push    rbx
        mov     ebx, edi
        mov     edi, 4
        sub     rsp, 8
        call    operator new(unsigned long)
        mov     DWORD PTR [rax], ebx
        mov     rdi, rax
        mov     rbp, rax
        call    foo(int*)
        add     rsp, 8
        pop     rbx
        pop     rbp
        ret
        mov     rdi, rax
        jmp     .L2

baz(int) [clone .cold]:
.L2:
        call    __cxa_begin_catch
        mov     esi, 4
        mov     rdi, rbp
        call    operator delete(void*, unsigned long)
        call    __cxa_rethrow
        mov     rbp, rax
        call    __cxa_end_catch
        mov     rdi, rbp
        call    _Unwind_Resume
```


And C++ style

```
#include <memory>

void foo(std::unique_ptr<int> ptr);

void baz(int value)
{
    foo(std::make_unique<int>(value));
}
```

The asm (/O3)

```
baz(int):
        push    rbp
        push    rbx
        mov     ebx, edi
        mov     edi, 4
        sub     rsp, 24
        call    operator new(unsigned long)
        lea     rdi, [rsp+8]
        mov     DWORD PTR [rax], ebx
        mov     QWORD PTR [rsp+8], rax
        call    foo(std::unique_ptr<int, std::default_delete<int> >)
        mov     rdi, QWORD PTR [rsp+8]
        test    rdi, rdi
        je      .L1
        mov     esi, 4
        call    operator delete(void*, unsigned long) <<<<<< Here, why do we
need to call the delete operator. It is `foo` who is responsible for that
.L1:
        add     rsp, 24
        pop     rbx
        pop     rbp
        ret
        mov     rbp, rax
        jmp     .L3
baz(int) [clone .cold]:
```

Reply via email to