126

Is this code correct?

auto v =  make_unique<int>(12);
v.release();     // is this possible?

Is it equivalent to delete of a raw pointer?

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Zeukis
  • 1,295
  • 2
  • 9
  • 8

5 Answers5

238

No, the code causes a memory leak. release is used to release ownership of the managed object without deleting it:

auto v = make_unique<int>(12);  // manages the object
int * raw = v.release();        // pointer to no-longer-managed object
delete raw;                     // needs manual deletion

Don't do this unless you have a good reason to juggle raw memory without a safety net.

To delete the object, use reset.

auto v = make_unique<int>(12);  // manages the object
v.reset();                      // delete the object, leaving v empty
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • 16
    As a completely off topic tangent, I've seen people write `int* raw` and `int *raw`, but that's the first time I've seen `int * raw` – Cory Kramer Sep 01 '14 at 16:03
  • 15
    @Cyber: It's a matter of taste. I don't regard the pointer qualifier as being "attached" to either the type or the variable, so I don't attach it to either. – Mike Seymour Sep 01 '14 at 16:04
  • 21
    If find it sad that they decided to use these function names. Something like `detach` would be much less misleading than `release`. – minexew Jul 13 '16 at 13:20
  • 1
    @eepp Would that destroy the object or just do like `release`? – tuket Jan 29 '19 at 20:42
  • @tuket See its declaration (`operator=()` accepting a `nullptr_t` parameter): _Effectively the same as calling `reset()`_. – eepp Feb 12 '19 at 23:53
  • Setting it to nullptr is much less clear and requires knowledge of the argument's meaning. – nenchev Oct 02 '19 at 17:29
  • 4
    I disagree @nenchev. I think assignment from nullptr is _more_ clear. There's literally nothing else it could do except delete the pointed-to object (it's unique_ptr) because it's obviously replacing the current value with nullptr. For reset(), you have to go read the docs to be sure exactly what that function does. – MadScientist Oct 09 '19 at 19:33
  • 1
    @MadScientist To be honest, after giving this a second thought, I agree with you. I guess my initial reaction was because reset() seems pretty explicit about resetting the contents of the unique_ptr, whereas setting it to nullptr didn't seem as explicit to me, but there's not much else it could mean now that I think about it. – nenchev Oct 11 '19 at 14:04
  • A shorthand for your 'release()' version: `delete v.release();` – Bart Jun 05 '23 at 09:18
38

Is this code correct?

No. Use std::unique_ptr<>::reset() to delete the internal raw pointer:

auto v =  std::make_unique<int>(12);
v.reset(); // deletes the raw pointer

After that is done, std::unique_ptr<>::get() will return nullptr (unless you provided a non-nullptr parameter to std::unique_ptr<>::reset()).

Johann Gerell
  • 24,991
  • 10
  • 72
  • 122
29

Is this code correct?

It is not, and will leak.

release() just lets go of the memory ownership that this unique_ptr held until it was called, and returns a pointer that the caller now is responsible for, including having to manually delete it.

If you don't assign the pointer returned by release(), you'll just have a leak.

An explicit delete for a unique_ptr would be reset(). But do remember that unique_ptr are there so that you don't have to manage directly the memory they hold. That is, you should know that a unique_ptr will safely delete its underlying raw pointer once it goes out of scope.

So you should have a very good reason to perform manual memory management on an automatic memory management object.

JBL
  • 12,588
  • 4
  • 53
  • 84
13

release will leak your raw pointer since you don't assign it to anything.

It is meant to be used for something like

int* x = v.release();

Which means v is no longer managing the lifetime of that pointer, it is delegating the raw pointer ownership to x. If you just release without assigning to anything, you leak the raw pointer.

Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
  • Ah I see. So in my code I've been using `.get()` followed by `.reset()` to swap things around, but really what I'm wanting to do is `.release()` followed by `.reset()`, to make sure the `.reset()` call doesn't then `delete` the old object. `.release()` then performs the same function as `.get()`, after releasing the pointer. – Andrew Oct 15 '20 at 17:09
  • or perhaps not `.reset()` but simple assignment post-`.release()`. – Andrew Oct 15 '20 at 17:11
  • A `.get()` followed by a `.reset()` will cause a problem. The `.get()` will give you a *non-owning* pointer, then `.reset()` will call `delete`, therefore your raw pointer from `get` is now a "dangling pointer" and accessing it is undefined behavior. – Cory Kramer Oct 15 '20 at 17:19
5

it may be a bit tricky for arbitrary types:

  unique_ptr<Foo> v = get_me_some_foo();  // manages the object
  Foo * raw = v.release();        // pointer to no-longer-managed object
  delete raw;

is almost correct.

  unique_ptr<Foo> v = get_me_some_foo();  // manages the object
  Foo * ptr = v.release();        // pointer to no-longer-managed object
  v.get_deleter() ( ptr );

this one would be correct in all situation; there may be a custom deleter defined on type Foo, but using the deleter returned by the unique_ptr object is good for all cases.

MichaelMoser
  • 3,172
  • 1
  • 26
  • 26