Search code examples
c++assemblylanguage-lawyerunique-ptr

Why does a function taking a std::unique_ptr by value not call the destructor in gcc/clang?


Looking at the assembly output of the following simple C++ function:

#include <memory>
int square(std::unique_ptr<int> num) {
    return *num * *num;
}

Gcc and clang emit the following assembly (-O2):

square(std::unique_ptr<int, std::default_delete<int> >):
        mov     rax, QWORD PTR [rdi]
        mov     eax, DWORD PTR [rax]
        imul    eax, eax
        ret

This was very unexpected for me: where is the destructor being called?

MSVC on the other hand does what I expected, and calls the destructor.

Here's a godbolt repro: https://godbolt.org/z/e66xh9Yos

I also tried using bigger types than int to see if it's some small size optimization, but that did not seem to be the case.

Can anybody explain what is going on here?


Solution

  • It is implementation-defined whether function parameter objects are destroyed at when a function returns or at the end of the full-expression containing the call to the function.

    In other words, it is an ABI decision whether or not the caller or the callee is responsible for calling the destructor.

    The Itanium C++ ABI (used everywhere except for MSVC as far as I am aware) chooses to destroy function parameter objects at the end of the full-expression containing the call. On the other hand MSVC's ABI chooses to destroy them when the function returns.

    The standard made it explicitly implementation-defined to support both of these ABI decisions retroactively.

    Also note that calling the constructor for the function parameter object is always responsibility of the caller. So the caller is able to call the destructor just as well as the callee is. It knows where the object has been constructed and what its type is from the function declaration.