Ajay
Ajay

Reputation: 18411

Reassign unique_ptr object with make_unique statements - Memory leak?

I don't get what following statement would do (specially second line)?

auto buff = std::make_unique<int[]>(128);
buff = std::make_unique<int[]>(512);

Will the second call to make_unique followed by assignment operator will de-allocate memory allocated by first call, or will there be memory leak? Must I have to use buff.reset(new int[512]); ?

I've debugged it, but didn't find any operator= being called, nor any destructor be invoked (by unique_ptr).

Upvotes: 22

Views: 10945

Answers (3)

V. Kravchenko
V. Kravchenko

Reputation: 1904

Move assignment operator is called, which does

if (this != &_Right)
{   // different, do the swap
    reset(_Right.release());
    this->get_deleter() = _STD move(_Right.get_deleter());
}

No leak here, as it does reset, which will deallocate.

Upvotes: 18

Richard Hodges
Richard Hodges

Reputation: 69884

gcc 5.3:

#include <memory>

extern void emit(int*);

int main()
{
    // declare and initialise buf
    auto buff = std::make_unique<int[]>(128);

    // make_unique on the RHS returns a temporary
    // - therefore an r-value reference

    // therefore this becomes and operator=(unique_ptr&&)
    // (move-assignment)
    buff = std::make_unique<int[]>(512);

    // something to get the compiler to emit code
    emit(buff.get());
}

yields assembly:

main:
        pushq   %r12
        movl    $512, %edi
        pushq   %rbp
        pushq   %rbx
        call    operator new[](unsigned long)  ; <-- new (1)
        movl    $64, %ecx
        movq    %rax, %rbp
        xorl    %eax, %eax
        movq    %rbp, %rdi
        rep stosq
        movl    $2048, %edi
        call    operator new[](unsigned long) ; <<-- new (2)
        movl    $2048, %edx
        xorl    %esi, %esi
        movq    %rax, %rdi
        movq    %rax, %rbx
        call    memset
        movq    %rbp, %rdi
        call    operator delete[](void*)       ;<-- delete (1)
        movq    %rbx, %rdi
        call    emit(int*)
        movq    %rbx, %rdi
        call    operator delete[](void*)       ;<-- delete (2)
        popq    %rbx
        xorl    %eax, %eax
        popq    %rbp
        popq    %r12
        ret
        movq    %rax, %r12
        movq    %rbp, %rbx
.L3:
        movq    %rbx, %rdi
        vzeroupper
        call    operator delete[](void*)       ;<-- handles a failed assignment
        movq    %r12, %rdi
        call    _Unwind_Resume
        movq    %rax, %r12
        jmp     .L3

Upvotes: 4

Smeeheey
Smeeheey

Reputation: 10316

There is no memory leak here, the assignment will deallocate the resources associated with the first allocation. Not seeing it in the debugger most likely means the relevant call was just optimised out. Try compiling with -O0 if you want to see it.

Upvotes: 9

Related Questions