Smart Pointers in C++ - Part 2
Introduction
Welcome to Part #2 of Smart Pointers in C++!
The Part #1 is a prerquisite for Part #2 and can be found here.
Let's learn some more about unique_ptr
and also other types of smart pointers available in C++.
unique_ptr
Some more usage scenarios for unique_ptr
Dynamically creating arrays with We can create arrays with raw pointers like so.
int main() {
int *arrPtr = new int[5];
// creates an int array of size 5
arrPtr[0] = 10;
arrPtr[1] = 11;
arrPtr[2] = 12;
arrPtr[3] = 13;
arrPtr[4] = 14;
// work with the array
for (int i = 0; i < 5; ++i)
{
std::cout << arrPtr[i] << '\n';
}
delete[] arr;
// don't forget to free the memory
}
Using unique_ptr
the code will be changed to
int main() {
// arrays
unique_ptr<int[]> arrPtr (new int[5]);
// creates an int array of size 5
arrPtr[0] = 10;
arrPtr[1] = 11;
arrPtr[2] = 12;
arrPtr[3] = 13;
arrPtr[4] = 14;
// work with the array
for (int i = 0; i < 5; ++i)
{
std::cout << arrPtr[i] << '\n';
}
}
Again, we don't free the memory by using delete[]
. That happens automatically as the unique_ptr
takes ownership of the array.
Using move constructor
We already saw the use of move assignment in Part #1. Let's see how a move constructor can be used for unique_ptr
.
/*
unique_ptr does not support copying. If one tries to copy a unique_ptr,
they'll get compiler error. However, it supports move semantics, where the
pointer is moved from one unique_ptr to another, which invalidates the
first unique_ptr
*/
unique_ptr<int> p1(new int(15));
unique_ptr<int> p1Now(std::move(p1));
std::cout << *p1Now; // 15
So we first created a new int, owned by p1
, using a constructor. Then we move constructed p1Now
to steal the memory owned by p1
. This operation invlaidates p1
. That's the reason we get 15
when we access the value owned by p1Now
. Trying to access the value owned by p1
after p1Now
is constructed, will result in runtime error.
Using arrow notations with smart pointers
We have seen that we can deference a smart pointer exactly the way we can dereference a raw pointer (using *
). We can also use the arrow notation (->
) on smart pointers just the way we use them on raw pointers.
unique_ptr<Person> personPtr (new Person("John Doe", 40));
std::cout << personPtr->getName() << '\n';
std::cout << "Age: " << personPtr->getAge() << '\n';
Some types of C++ Standard Library smart pointers
It is recommended to use the following smart pointers in favour of raw pointers when wrting C++ code.
unique_ptr
As we have already seen,unique_ptr
allows exactly one owner for a specific resource. This is the default choice for any resource unless one knows for sure that ashared_ptr
is needed. Does not support copying, only move semantics are supported.shared_ptr
When we would like to have multiple smart pointers co-owning a resource, we have to useshared_ptr
. These are reference-counted smart pointers (more about this later). The owned resources is not deleted until all owners have gone out of scope or have otherwise given up ownership.weak_ptr
This smart pointer can be used along withshared_ptr
. It does not participate in reference counting. Aweak_ptr
can be used when we want access to an object but don't want the smart pointer to take ownership of the object.
Stay tuned for knowing more shared_ptr
and weak_ptr
.
Want to know more now? Follow the link