Smart Pointers

Smart pointers are modern C++ solving the main problem with raw pointers, memory management and remembering to free heap memory with delete. They should be preferred in any new program.

Unique Pointers

  • At any given moment, there can be only one pointer managing the memory.
  • Memory is automatically released when the pointer goes out of scope.
  • To use unique pointers include the memory header.

Some ways of initializing unique pointers are show below:

std::unique_ptr<Point> p_point { new Point(3, 5) };
std::unique_ptr<Point> p_point2 { nullptr };
std::unique_ptr<Point> p_point3 = std::make_unique<Point>(3, 5);

Using the make_unique function is preferred. We can then use the smart pointer like any other pointer. We can use the arrow operator to call methods and the dereference operator to access what is being pointed at. If you need to pass a raw pointer to a library function, you can get access to it using the get method. We can call reset on the unique pointer to release the memory and set it nullptr. We can test the pointer to see if it’s valid:

if (p_point) {
    std::cout << "Pointer is valid " << p_point.get() << std::endl;
} else {
    std::cout << "Pointer is invalid " << p_point.get() << std::endl;
}

When passing unique pointers as function parameters, passing by value is not allowed as we can’t make copies of a unique pointer. There will be a compiler error. We can transfer ownership to the pointer in the function by using std::move, but this will free up the memory when the function ends and is typically not wanted. We can also pass a unique pointer by reference which works as expected.

We can try to return a unique pointer by copy, it will probably work due to compiler optimizations returning a kind of reference. Not all compilers do this, so you may get a compiler error.

Shared Pointers

  • At any given moment, there can be many pointers managing the memory.
  • Memory is automatically released when the last pointer goes out of scope.
  • To use shared pointers include the memory header.

Some ways of initializing shared pointers are show below:

std:sharede_ptr<Point> p_point { new Point(3, 5) }; 
std::shared_ptr<Point> p_point2 { nullptr }; 
std::shared_ptr<Point> p_point3 = std::make_shared<Point>(3, 5);

Copies are allowed as there can be more than one shared pointer pointing to the same data. The copies are kept track of by a reference count which we can access using the use_count method. If we use the rest method, it will null out the pointer and decrement the reference count. As with the other types of smart pointers, we can go through the get method to access the raw pointer so we can pass it to a library function.

We can create a shared pointer from a unique pointer by using std::move:

std::unique_ptr<Point> up = make_unique<Point>(5, 3);
std::shared_ptr<Point> sp = std::move(up);

But we can’t go the other way because we could have more than one pointer pointing to the memory.

When passing shared pointers as function parameters, passing by value is allowed as we can make copies of a shared pointer. We can also pass a unique pointer by reference which works as expected. If we have to return smart pointers from functions, then return a unique pointer. It gives you the flexibility to use shared pointers.

Weak Pointers

Non owning pointers that don’t implement the -> and * operators. We can’t use them to read or write the data. Initialized from shared pointers, these …. If you want to use a weak pointer you have to turn it back to a shared pointer using the lock method. Weak pointers are used to solve cyclic dependencies.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.