unique_ptr is one of the smart pointers provided by C++ 11 to prevent memory leakage. It is a smart pointer that exclusively enjoys the ownership of the managed object pointer. unique_ The PTR object wraps a raw pointer and is responsible for its life cycle. When the object is destroyed, the associated original pointer is deleted in its destructor.
unique_ptr has - > and * operator overloads, so it can be used like a normal pointer.
#include <iostream> #include <memory> struct Task { int mId; Task(int id ) :mId(id) { std::cout << "Task::Constructor" << std::endl; } ~Task() { std::cout << "Task::Destructor" << std::endl; } }; int main() { // Create unique from original pointer_ PTR instance std::unique_ptr<Task> taskPtr(new Task(23)); //Through unique_ptr access its members int id = taskPtr->mId; std::cout << id << std::endl; return 0; } Output: Task::Constructor 23 Task::Destructor
unique_ The PTR < task > object taskPtr accepts the original pointer as a parameter. Now, when the main function exits, the object will call its destructor when it is out of scope. In unique_ In the destructor of taskPtr of PTR object, the associated original pointer will be deleted, so there is no need to specifically delete the task object.
In this way, whether the function exits normally or abnormally (due to some exceptions), the destructor of taskPtr will always be called. Therefore, the original pointer will always be deleted and memory leakage will be prevented.
unique_ptr exclusive ownership
unique_ The PTR object is always the sole owner of the associated original pointer. We can't copy unique_ptr object, which can only move.
Because each unique_ptr objects are the only owner of the original pointer, so it directly deletes the associated pointer in its destructor without any reference count.
Create an empty unique_ptr object
Create an empty unique_ The PTR < int > object is empty because it has no original pointer associated with it.
Check unique_ Is the PTR object empty
There are two ways to check unique_ Whether the PTR object is null or has an original pointer associated with it.
// Method 1 if(!ptr1) std::cout<<"ptr1 is empty"<<std::endl; // Method 2 if(ptr1 == nullptr) std::cout<<"ptr1 is empty"<<std::endl;
Create unique using the original pointer_ PTR object
To create a non empty unique_ptr object, you need to pass the original pointer in its constructor when creating the object, that is:
std::unique_ptr taskPtr(new Task(22));
Using std::make_unique create unique_ptr object / C++14
std::unique_ptr taskPtr = std::make_unique(34);
Gets the pointer to the managed object
Use the get() · function to get the pointer of the management object
Task *p1 = taskPtr.get();
Reset unique_ptr object
In unique_ Calling the reset() function on the PTR object will reset it, that is, it will release the original pointer associated with delete and make unique_ptr object is empty
taskPtr.reset();
unique_ptr object is not replicable
Because unique_ptr cannot be copied and can only be moved. Therefore, we cannot create unique by copying constructors or assignment operators_ A copy of the PTR object.
// Compilation error: unique_ptr cannot be copied std::unique_ptr<Task> taskPtr3 = taskPtr2; // Compile error // Compilation error: unique_ptr cannot be copied taskPtr = taskPtr2; //compile error
Transfer unique_ Ownership of PTR objects
We can't copy unique_ptr objects, but we can transfer them. This means unique_ The PTR object can transfer ownership of the associated original pointer to another unique object_ PTR object. Let's understand through an example
// Create taskPtr2 from the original pointer std::unique_ptr<Task> taskPtr2(new Task(55)); // Transfer ownership of the associated pointer in taskPtr2 to taskPtr4 std::unique_ptr<Task> taskPtr4 = std::move(taskPtr2); // The pointer associated with taskPtr2 is now null if(taskPtr2 == nullptr) std::cout<<"taskPtr2 is empty"<<std::endl; // Ownership of the taskPtr2 Association pointer is now transferred to taskPtr4 if(taskPtr4 != nullptr) std::cout<<"taskPtr4 is not empty"<<std::endl; // Will output 55 std::cout<< taskPtr4->mId << std::endl;
std::move() will convert taskPtr2 into an R-value reference. Therefore, unique is called_ PTR and transfer the associated original pointer to taskPtr4. After transferring ownership of the original pointer, taskPtr2 will become null.
Release the associated original pointer
In unique_ Calling release() on the PTR object releases ownership of its associated original pointer and returns the original pointer. Here is the release of ownership. There is no delete original pointer. reset() will delete the original pointer.
std::unique_ptr<Task> taskPtr5(new Task(55)); // Not empty if(taskPtr5 != nullptr) std::cout<<"taskPtr5 is not empty"<<std::endl; // Release ownership of associated pointers Task * ptr = taskPtr5.release(); // Empty now if(taskPtr5 == nullptr) std::cout<<"taskPtr5 is empty"<<std::endl;
Sample program
#include <iostream> #include <memory> struct Task { int mId; Task(int id ) :mId(id) { std::cout<<"Task::Constructor"<<std::endl; } ~Task() { std::cout<<"Task::Destructor"<<std::endl; } }; int main() { // Empty object unique_ptr std::unique_ptr<int> ptr1; // Check whether ptr1 is empty if(!ptr1) std::cout<<"ptr1 is empty"<<std::endl; // Check whether ptr1 is empty if(ptr1 == nullptr) std::cout<<"ptr1 is empty"<<std::endl; // Unique cannot be initialized by assignment_ ptr // std::unique_ptr<Task> taskPtr2 = new Task(); // Compile Error // Create unique from original pointer_ ptr std::unique_ptr<Task> taskPtr(new Task(23)); // Check whether taskPtr is empty if(taskPtr != nullptr) std::cout<<"taskPtr is not empty"<<std::endl; // Access unique_ Member of PTR Association pointer std::cout<<taskPtr->mId<<std::endl; std::cout<<"Reset the taskPtr"<<std::endl; // Reset unique_ptr is null, the associated original pointer will be deleted taskPtr.reset(); // Check for null / check for associated raw pointers if(taskPtr == nullptr) std::cout<<"taskPtr is empty"<<std::endl; // Create unique from original pointer_ ptr std::unique_ptr<Task> taskPtr2(new Task(55)); if(taskPtr2 != nullptr) std::cout<<"taskPtr2 is not empty"<<std::endl; // unique_ptr objects cannot be copied //taskPtr = taskPtr2; //compile error //std::unique_ptr<Task> taskPtr3 = taskPtr2; { // Transfer ownership (transfer pointer in unique_ptr to another unique_ptr) std::unique_ptr<Task> taskPtr4 = std::move(taskPtr2); // Empty after transfer if(taskPtr2 == nullptr) std::cout << "taskPtr2 is empty" << std::endl; // Not empty after transfer in if(taskPtr4 != nullptr) std::cout<<"taskPtr4 is not empty"<<std::endl; std::cout << taskPtr4->mId << std::endl; //taskPtr4 goes beyond the following parenthesis to delete the pointer associated with it } std::unique_ptr<Task> taskPtr5(new Task(66)); if(taskPtr5 != nullptr) std::cout << "taskPtr5 is not empty" << std::endl; // Release ownership Task * ptr = taskPtr5.release(); if(taskPtr5 == nullptr) std::cout << "taskPtr5 is empty" << std::endl; std::cout << ptr->mId << std::endl; delete ptr; return 0; } output: ptr1 is empty ptr1 is empty Task::Constructor taskPtr is not empty 23 Reset the taskPtr Task::Destructor taskPtr is empty Task::Constructor taskPtr2 is not empty taskPtr2 is empty taskPtr4 is not empty 55 Task::Destructor Task::Constructor taskPtr5 is not empty taskPtr5 is empty 66 Task::Destructor
summary
The new object is located on the heap memory. You must call delete to free its memory.
unique_ptr is a container containing pointers and has the unique ownership of associated pointers. When used as a common variable, the system allocates objects to the stack memory. When it exceeds the scope, it will be automatically destructed, unique_ The destructor of PTR object will delete its associated pointer, which is equivalent to deleting the object in heap memory for us.
unique_ptr cannot be copied directly. You must use std::move() to transfer its managed pointer. After the transfer, the original unique_ptr is empty. std::unique_ptr<Task> taskPtr4 = std::move(taskPtr2);
How to create an object:
//C++11: std::unique_ptr<Task> taskPtr(new Task(23)); //C++14: std::unique_ptr<Task> taskPtr = std::make_unique<Task>(34);