Doesn't this defeat the whole purpose behind std::unique_ptr ? Why is this allowed?

Edit: I thought the whole purpose behind std::unique_ptr was to have sole ownership of an object. But this example, the object can be modified through another pointer. Doesn't this defeat std::unique_ptr's purpose?

Because int* myPtr = intPtr.operator->(); would be harder to read? unique_ptr has no choice but to expose the raw pointer in some way - otherwise, how would you access anything pointed to?
–
Igor TandetnikAug 18 '14 at 19:28

7

unique_ptr doesn't exist to prevent aliasing. It exists to allow one (and only one) "owner" of object lifetime. myPtr doesn't "own" the lifetime of the int.
–
CornstalksAug 18 '14 at 19:31

2

If I invite you to have a lunch in my home, you modify the content on my house, without being owner ...
–
Emilio GaravagliaAug 18 '14 at 19:41

Pass by * or & to accept a widget independently of how the caller is
managing its lifetime. Most of the time, we don’t want to commit to a
lifetime policy in the parameter type, such as requiring the object be
held by a specific smart pointer, because this is usually needlessly
restrictive.

Passing a unique_ptr by value is only possible by moving the object
and its unique ownership from the caller to the callee. Any function
like (c) takes ownership of the object away from the caller, and
either destroys it or moves it onward to somewhere else.

and finally pass a unique_ptr by reference when we can potentially modify it to refer to a different object:

This should only be used to accept an in/out unique_ptr, when the
function is supposed to actually accept an existing unique_ptr and
potentially modify it to refer to a different object. It is a bad way
to just accept a widget, because it is restricted to a particular
lifetime strategy in the caller.

Of course, we are required to get the underlying pointer if we have to interface with C libraries that take pointers.

In your specific example:

int* myPtr = intPtr.get();

There is no transfer of ownership to another smart pointer so there are no problems as long as you don't attempt to delete the pointer via myPtr. You can transfer ownership to another unique_ptr by moving it:

This doesn't defeat the purpose of unique_ptr at all. The type of smart pointer determines the ownership semantics, but there may be a case where you need to use the underlying object. For example you have an object owned by a unique_ptr but need to call a method that expect the object by reference. You can then dereference the .get() pointer to get the reference object to pass to the method.

What you shouldn't do is store the obtained pointer in a way that acquires ownership. This is one of the cases where the language gives you tools to work properly and if you take the raw pointer and store a second ownership to it then that's a problem with the use of the tool.

The example you have shown does not defeat the purpose of std::unique_ptr, which is to maintain ownership of memory allocation and deallocation. The line std::unique_ptr<int> intPtr{new int(3)} allocates a new int and takes ownership of it.

The line *myPtr = 4 does not change that ownership, it is merely assigning a value to the content of the int, via a pointer retrieved by std::unique_ptr::get(). The std::unique_ptr still owns the allocated memory for the int.

Get just allows you to obtain the raw pointer. Otherwise, you wouldn't be able to use a pointer-based API when you have a unique_ptr, as the only alternative is release, which would make the unique pointer useless. So you get get, which allows using pointer-based APIs without forcing everyone to use an unique_ptr. Without get, you could only call -> and * on the pointer, but if you have a primitive type, that would kind of defeat of having an unique_ptr in the first place.