C++ smart pointer std::unique_ptr does everything which std::auto_ptr does, plus it also takes care of exclusive ownership of pointer. Clearly, a unique_ptr always exclusively owns the data it is pointing to. It must be noted that an explicit move operation is needed to transfer the ownership of data to another unique_ptr. (This point will be elaborated in a while)
Header file to be included to use unique_ptr:
#include <memory>
How to initialize unique_ptr ?
Any of the following 3 syntax can be used:
Using simple new Operator (from C++11)
std::unique_ptr<T> up1 (new T (constructor arguments));
Using make_unique function (from C++14)std::unique_ptr<T> up1 = std::make_unique<T> (constructor arguments);
auto up1 = std::make_unique<T> (constructor arguments);
Advantages of using make_unique instead of new:
- This perfect forwards the arguments
- This is more cleaner approach
- Takes care of exception safety
Basic implementation of std::make_unique
This is easy to write as shown below:
template <typename T, typename… Ts)
std::unique_ptr make_unique(Ts&&... params)
{
return std::unique_ptr(new T(std::forward(params)...));
}
Transfer of ownership
The following command will not work because here the content of up1 is being assigned to up2. The content of up1 are exclusively owned and no other pointer can refer it. Therefore, compiler will throw an error:
std::unique_ptr<int> up2 = up1;
Note: the auto_ptr would have worked and would have make the up1 dangling.
Explicit transfer need to be done using move function, the following command will work:
std::unique_ptr<int> up2 = std::move(up1);
The up1 will become null and any further reference to up1 will result in undefined behavior. up2 will now exclusively own the resource.
How to print actual memory of actual data:
The memory address can be printed with get( ) function as shown in below example.
#include <iostream> //main header
#include <memory> // for unique ptr
using namespace std;//for namespace
int main() //main function
{
auto up1 = std::make_unique<int>();
std::unique_ptr<int> up2 = std::move(up1);
cout << up1.get() << endl; //Prints memory address of up1
cout << up2.get() << endl; //Prints memory address of up2
return 0;
}
Output:
0
0x1943c20
Providing custom delete to unique_ptr
By default, resource destruction takes place via standard delete, but custom deleters can be specified. However, stateful deleters and function pointers as deleters increase the size of std::unique_ptr objects.
Example, with simple functor:
struct MySimpleDeleter {
void operator()(int* ptr) const {
printf("Deleting int pointer with functor!\n");
delete ptr;
}
};
std::unique_ptr<int, MySimpleDeleter> up1 (new int);
The output will be :
Deleting int pointer with functor!
Example with Lambda
auto lambdadeleter = [](int *a)
{
delete a;
cout << ""Deleting int pointer with Lambda!" << endl;
};
std::unique_ptr<int, decltype(lambdadeleter) > up1 (new int, lambdadeleter);
The output will be:
Deleting int pointer with Lambda!