While Smart Pointers control the lifetime of the pointed object, it is often still useful to have access to a basic raw pointer.
In fact, if we read Herb Sutter GotW # 91 Solution: Smart Pointer parameters, he recommends passing parameters by pointer or reference, when the function is agnostic to the parameter lifetime, he says:
Skip * or or accept the widget no matter how the caller controlling his life expectancy. In most cases, we do not want a lifetime policy in the parameter type, for example, requiring the object to be stored in a specific smart pointer, because it is usually useless restrictive.
and we must pass unique_ptr when the function is a receiver:
The transfer of the unique_ptr value is only possible when moving the object and its unique property from the caller. Any function, for example, (c) obtains ownership of the object from the caller and either destroys it or moves it further to another location.
and finally pass unique_ptr by reference when we can change it to reference another object:
This should only be used to accept in / out unique_ptr when a function should actually accept an existing unique_ptr and potentially modify it to refer to another object. This is a bad way to simply accept a widget, as it is limited to a specific life strategy in the caller.
Of course, we need to get the main pointer if we need to interact with C libraries that accept pointers.
In your specific example:
int* myPtr = intPtr.get();
There is no transfer of ownership to another smart pointer, so there is no problem if you are not trying to execute the delete pointer through myPtr . You can transfer ownership to another unique_ptr by moving it:
std::unique_ptr<int> intPtr2( std::move( intPtr ) ) ;