Declaration and Uses of unique_ptr in C++

Shikha Chaudhary Feb 16, 2024
  1. Declaration and Uses of unique_ptr in C++
  2. Unique Pointers in C++
  3. Conclusion
Declaration and Uses of unique_ptr in C++

Pointers serve many useful purposes in C++. From saving space in programs to helping implement data structures, pointers are a very important tool for programming languages like C and C++.

This article will discuss the concepts of one such pointer, the unique pointer. The standard library of C++ provides this pointer as one of the implementations of the smart pointers.

Wondering what these smart pointers are now? Read on; we got everything covered for you.

Declaration and Uses of unique_ptr in C++

We already know that pointers are used to store addresses of other variables. Although these pointers are useful in many places, they have a major issue.

Look at the given block of code. Most of the time, we declare a pointer as follows and then use it but never delete it.

void demo() {
  int *d = new int;
  *d = 10;
}

This leads to the problem of memory leaks. It occurs when a memory section is not deallocated or freed after use.

Thus, the memory neither available for any other program nor free leads to space waste and slows down performance. This is nothing but a memory leak.

When the programs are more complex, this may even lead to the entire heap memory becoming useless. Thus, C++11 came up with the concept of smart pointers to counter this problem.

Smart Pointers in C++

Languages like Java and C# have a mechanism through which the unused memory is automatically deallocated. So, the programmer needs not to deallocate pointers, which the Garbage collection system will take care of.

For C++, this is achieved through the use of smart pointers. Smart pointers are nothing but simple classes that wrap the raw pointers and overload operators like * and ->.

The objects of a smart pointer class appear to be the same as the normal pointers, but unlike normal pointers, they can themselves deallocate the unused memory space. Four types of smart pointers are defined inside the <memory> header of the standard library of C++, of which unique_ptr is one.

Now, we are all set to begin learning about the unique pointer of C++.

Unique Pointers in C++

A unique_ptr was developed to replace the auto_ptr of C++. Unlike raw pointers, the unique_ptr is a container for raw pointers and guarantees exclusive ownership and no memory leak.

Declaration of unique_ptr in C++

The below code shows how we declare a unique pointer in C++.

std::unique_ptr<Type> p(new Type);

Here, if we want to create a unique pointer that points to an integer, say 10, then this is how the above syntax would change.

std::unique_ptr<int> p(new int(10));

The above line of code means a unique pointer, p, points to the value 10. You must understand how this basic declaration works.

The new expression creates the pointer p in this above line of code. But the meaning changes if we change the same declaration to the one given below.

std::unique_ptr<int> p2(x);

Now here, the pointer gets stored in the variable x. Conceptually, things are the same.

We are making a unique_ptr at both places, but using the second method is not advisable.

Using the second method, we can do something like this:

std::unique_ptr<int> p2(x);
std::unique_ptr<int> p3(x);
//....
std::unique_ptr<int> p6(x);

This means that more than one unique pointer owns the same object, which is against the semantics of a unique pointer, as you will see in the following sections.

Also, in C++14, we have an option to use make_unique to declare a unique_ptr like this:

unique_ptr<int> d = make_unique<int>(10);

This creates a unique pointer d that points to the value 10.

Let us now look at the various features of the unique_ptr one by one.

Auto Deletion of the C++ unique_ptr

With raw pointers, programmers often forget to delete the pointer after use, leading to the memory leak problem. The unique_ptr saves this hassle as it destroys the object it holds when the unique_ptr goes out of scope.

The object is destroyed when the unique_ptr is destroyed, or another pointer is assigned to the unique_ptr. This is done with the help of get_deleter() (ptr), which uses the delete operator to destroy the object and deallocate the memory.

Thus, when you use a unique_ptr, you do not have to delete dynamically allocated objects, and the destructor of unique_ptr will take care of that.

Below is an illustrated code that shows the scope outside which the pointer is destroyed.

void demo() { unique_ptr<int> demo(new int); }
< -- -- -- -- -- -- -- -- -- -- -- -- -scope of the pointer ends here

The object is destroyed when the control goes out of these curly braces.

Exclusive Ownership of the C++ unique_ptr

The next and very important feature of unique_ptr provides exclusive ownership to an object and can’t be copied. This means that only one unique_ptr can simultaneously point to only one object.

This is also why we cannot copy a unique_ptr. Often with raw pointers, normal assignment leads to copying the pointer.

But this is not the case with unique_ptr. Look at this example.

Here, we have two unique pointers, p1 and p2, and we copy or assign the first pointer to the second one.

#include <iostream>
#include <memory>

using namespace std;

int main() {
  unique_ptr<int> p1(new int);
  unique_ptr<int> p2 = p1;
  cout << "Success";
  return 0;
}

Output:

use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]'
    8 |     unique_ptr<int> p2 = p1;

You can see that we get a compile-time error, and the print statement is not executed. This clearly shows that we cannot copy a unique_ptr in C++, which simultaneously points to only one object.

Now, had we done this with a raw pointer, the print statement would have been successfully executed. This is done below.

#include <iostream>
using namespace std;

int main()

{
  int *ptr1;
  int *ptr2;
  ptr2 = ptr1;
  cout << "Success";
  return 0;
}

Output:

Success

This time the pointers are copied because they are raw pointers. This is essentially how unique_ptr works when it comes to duplication.

Transfer of Ownership of the C++ unique_ptr

As seen previously, we cannot change the ownership of a unique_ptr by simply copying them. The solution here is to use the move() function provided by the standard library of C++.

We are taking the same code where we tried copying a unique_ptr using the assignment operator. However, this time, we will use the move() function during this assignment.

#include <iostream>
#include <memory>

using namespace std;

int main() {
  unique_ptr<int> p1(new int);
  unique_ptr<int> p2 = move(p1);  // using the move() function
  cout << "Success";
  return 0;
}

Output:

Success

Now, since we have used the move() function, we do not get any error, and the print statement also executes.

This is how we can transfer the ownership of an object to another unique_ptr, but in any case, the object that a unique_ptr points to remains one at a time.

These were the main features of the unique_ptr that make them different from raw pointers.

Refer to this documentation to know more about unique pointers.

Conclusion

In this article, we went through the concept of the unique pointer in C++. A unique pointer is a smart pointer known for its exclusive ownership and auto-deletion functionalities.

We learned how it is declared and how we can still transfer the ownership of a unique pointer using the move() function. Hope you will be able to use the unique pointer when required now that you know their features.

Related Article - C++ Pointer