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++.
Some more usage scenarios for unique_ptr
Dynamically creating arrays with unique_ptr
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_ptrallows exactly one owner for a specific resource. This is the default choice for any resource unless one knows for sure that ashared_ptris 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_ptrcan 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
