What is the C++ unique_ptr?

Learn via video course
FREE
View all courses
C++ Course: Learn the Essentials
C++ Course: Learn the Essentials
by Prateek Narang
1000
5
Start Learning
C++ Course: Learn the Essentials
C++ Course: Learn the Essentials
by Prateek Narang
1000
5
Start Learning
Topics Covered

Overview

Pointers have multiple purposes in C++ language like storing the memory address of an object, allocation of new objects on heap memory, and accessing them. But it is possible for raw pointers to cause memory leaks and bugs due to improper disposal of pointers which may cause the program to crash. Therefore to make sure that the pointers are deleted properly after their use we have a concept of smart pointers in C++ 11.

To understand the concept of unique_ptr let's have an overview of smart pointers.

Smart pointers manage the lifetime of raw pointers by wrapping them in a class and eliminating the possibility of memory leaks.

Here the idea of smart pointers brings together the overloaded operators like * and -> and destructor into one class, so that when an object leaves the scope, the destructor will be automatically triggered, and memory that was allocated dynamically will be deleted.

Now, let's see what is the role of unique_ptr as a smart pointer.

Introduction

A Unique pointer is a smart pointer that helps us manage memory by preventing memory leaks. unique_ptr contains a raw pointer and when this object is no longer in scope, then the pointer is deallocated.

As a replacement for std::auto_ptr, std::unique_ptr was introduced in C++11. Unique_ptr is a container that holds raw pointers and prevents copying of that pointer.

The underlying unique pointer stores only one raw pointer. As you can see in the diagram below that the two pointers cannot be assigned to one object. But if we remove the ownership from P1 then the ownership will automatically transfer to another pointer that is pointing to it but both P1 and P2 can't own the object together. introduction to C++ unique_ptr

Syntax

The unique_ptr type follows the following syntax.

When to Use unique_ptr?

If you want to have exclusive ownership (a single owner), use unique_ptr. There can only be one unique_ptr per resource. It is not possible to copy one unique_ptr to another since one unique_ptr can only belong to a single resource.

What is the Working of C++ unique_ptr?

Let's understand how the unique_ptr works.

Unique Pointers are Defined as -

Unique pointers

The allocated object on the heap is destroyed if the unique pointer is destroyed.

Unique pointers memory

It is not possible to copy unique_ptr since there can only be one unique_ptr per resource. If you do so it will cause compile time error.

Instead, It is possible to move one unique_ptr to another unique_ptr by using std::move().

In other words, unique_ptr should be used when we want to keep a single pointer to an object that can be reclaimed if the single pointer is destroyed.

Now let's have a look at other operations that can be performed with unique_ptr.

Operations with unique_ptr

Using std::swap()

This method exchanges two unique_ptr objects' contents of the same type, effectively transferring ownership between the two objects without destroying either. A swap operation is applied to the stored pointers and deleters by invoking the swap() function.

Code -

Output -

Explanation:- In the above C++ program, we have two unique pointer objects Obj1 and Obj2 which holds the value 65 and 90 respectively. After the std::swap() method is invoked the values of Obj1 and Obj2 are swapped.

Passing unique_ptr to a Function

You can pass std::unique_ptr by value if you want the function to own the pointer.

Code -

Output-

Explanation:-

In the above C++ program, we have passed the unique pointer as a value to the function Pass_ptr() so that the ownership of the pointer is passed to the function. Since ownership was transferred to Pass_ptr(), rather than the end of main(), the resource a was destroyed when Pass_ptr() is finished. Now, in the main() function the variable will need to be passed in using std::move since copy semantics is not allowed by unique_ptr.

Returning unique_ptr from a Function

Unique pointers can be returned by functions. As a result, it surrenders ownership of the pointer.

Code -

Output

Explanation:- In the above C++ program, the function Demo() is returning the unique_ptr by value. If this value isn't assigned to anything, the temporary return value will be removed from the scope. But in the program, it is assigned to x and hence value is returned.

Examples of C++ unique_ptr

Example 1: Manual Deallocation of Memory after Pointer is No Longer in Scope Using Delete (not using unique_ptr)

In the below C++ code, we are manually de-allocating the memory (by calling destructor manually) after the pointer is no longer in scope using the delete operator.

Code -

Output-

Explanation -

Here the object of class Demo is created which is present in the heap memory whose address is pointed by pointer f. But after the use of the pointer is over and it is no longer in scope we are deallocating the memory by calling the destructor manually using delete to prevent the memory leak.

Example 2: Deallocation of Memory After Pointer is No Longer in Scope Using unique_ptr

In this example, the use of unique_ptr is explained as how it functions for the deallocation of memory after the pointer is no longer in scope.

Code -

Output-

Explanation - In the above C++ code, we are de-allocating memory using unique_ptr (unlike using delete). The class Demo has an integer variable named an in it. When we create an object of class Demo, we don't create a normal object. Instead, we create a unique_ptr object that wraps a raw pointer p that points to the object of class Demo. After the pointer is no longer in scope the destructor is automatically called as you can see in the output.

Example 3: C++ Program to Illustrate Deallocation of Memory After Pointer is No Longer in Scope Using make_unique

In the below C++ program, the make_unique is used to achieve the same results as unique_ptr, as in make_unique is equivalent to unique_ptr.

Code -

Output-

Explanation:- This program is the same as the above program it's just written to show that the make_unique functions the same as unique_ptr.

Example 4: C++ Program to Illustrate the Transfer of the Ownership of an Object from One Unique Pointer to Another.

In the below C++ code, we are transferring the ownership of an object from one unique pointer to another using std::move(). Here upon ownership transfer, the smart pointer transferring ownership becomes null.

Code -

Output -

Explanation - In the above C++ program, we have a class named Demo inside which there is a method named hello() which prints Hello. Now in the main() function the unique pointer p1 points to the object of class Demo whose address can be obtained by the get() method. Now, there is another unique_ptr p2 that takes ownership of the object from p1 by using move(). Therefore p1 becomes null and p2 now has address of p1.

Misusing unique_ptr

Std::unique_ptr can be misused in two ways that can be easily avoided

1. Make Sure No More Than One Class Manages the Same Resource -

Despite being the above code syntactically legal, both res_1 and res_2 will try to delete the Resource.

2. The Resource Should Not Be Manually Deleted from Underneath the std::unique_ptr

In this case, std::unique_ptr will attempt to delete a resource that has already been deleted.

Conclusion

  • std::unique_ptr was introduced in C++11. Unique_ptr is a container that holds raw pointers and prevents copying of that pointer.
  • There can only be one unique_ptr per resource. It is not possible to copy one unique_ptr to another since one unique_ptr can only belong to a single resource.
  • It is possible to move one unique_ptr to another unique_ptr by using std::move().
  • If the allocated object on the heap is destroyed if the unique pointer is destroyed.
  • The unique_ptr can be misused if in the program more than one class manages the same resource or the resource is manually deleted from underneath the std::unique_ptr.