6

As far as I know, calling std::unique_ptr<T,Deleter>::release only transfers ownerships, won't free the dynamic memory.

From C++ Primer 5th:

p2.release(); // WRONG: p2 won't free the memory and we've lost the pointer
auto p = p2.release(); // ok, but we must remember to delete(p)

But after a few pages it writes:

The library provides a version of unique_ptr that can manage arrays allocated by new. To use a unique_ptr to manage a dynamic array, we must include a pair of empty brackets after the object type:

// up points to an array of ten uninitialized ints
unique_ptr<int[]> up(new int[10]);
up.release();   // automatically uses delete[] to destroy its pointer

The brackets in the type specifier (<int[]>) say that up points not to an int but to an array of ints. Because up points to an array, when up destroys the pointer it manages, it will automatically use delete[].


So is it true that std::unique_ptr<T,Deleter>::releas treats dynamically allocated array differently, which is freeing the allocated memory automatically after calling release()? If it's true, then it also indicates that one can't transfer ownership of an dynamic array. I couldn't find any authoritative references on the Web so far.

Rick
  • 7,007
  • 2
  • 49
  • 79
  • 1
    I think it's not true. I can't find it documented on cppreference and I can't reproduce: [wandbox](https://wandbox.org/permlink/FvhgwlKmbwKg9QkL). Destructor is not called. Memory is leaked. – Thomas Sablik Dec 11 '19 at 06:12
  • 2
    release -> reset typo – CinCout Dec 11 '19 at 06:17

2 Answers2

19

I looked a little in this, and I'm guessing this was just a mistake on the author's part. cppreference.com makes no reference to any array specialization for release. Just to make sure, I went ahead and checked the source code for libc++ (LLVM's implementation of the standard library). This is the implementation for std::unique_ptr<T[], Deleter>::release. As you can see, it does not call delete[]. My guess is the author meant to write up.reset();, as this does free the memory.

LRFLEW
  • 1,251
  • 3
  • 11
  • 19
8
// up points to an array of ten uninitialized ints
unique_ptr<int[]> up(new int[10]);
up.release();   // automatically uses delete[] to destroy its pointer

This is incorrect. up.release() is not calling delete[] for the array it manages. It is simply releasing ownership of the array and returning a pointer to it. It is, therefore, the responsibility of the coder to call delete[].

I think you are getting mixed up with std::unique_ptr<T, Deleter>::reset() which does free the allocated memory.

Demo:

#include <iostream>
#include <memory>

class Test
{
public:
    Test() { std::cout << "Test()" << std::endl; }
    ~Test() { std::cout << "~Test()" << std::endl; }
};

int main()
{
    std::unique_ptr<Test[]> up(new Test[3]);
    auto ptr = up.release();

    return 0;
}

Output:

Test()
Test()
Test()

The destructor is not called. So we have a memory leak! The only way to avoid this is to call delete[] ptr; after auto ptr = up.release();

Note: from C++14 onward you can write:

std::unique_ptr<CTest[]> up = std::make_unique<CTest[]>(3);

This is better than explicitly new-ing because it will not leak if an exception is thrown.

jignatius
  • 6,304
  • 2
  • 15
  • 30