Your browser doesn't support JavaScript Smart Pointers – Windows Programming

Smart Pointers

A smart pointer is a C++ class that manages a pointer to a dynamically allocated object. Unlike raw pointers, smart pointers can automatically release the dynamically allocated object when it is no longer required. Smart pointers help to manage the lifetime of dynamically allocated objects and reduce the risk of memory leaks.

C++11 introduced three main types of smart pointer, all of which are defined in the <memory> header provided by the Standard Library:

unique_ptr

A unique_ptr is a smart pointer that has exclusive ownership of an object. When the unique_ptr is destroyed, the object it owns is automatically destroyed. The owned object can also be explicitly released by calling reset().

A unique_ptr cannot be copied because there can only be one unique_ptr that owns the object. Ownership can, however, be transferred from one unique_ptr to another using std::move().

The syntax for std::unique_ptr in C++ is:

std::unique_ptr pointerName = std::make_unique(arguments);

std::unique_ptr pointerName = std::make_unique(arguments);

For example:

#include <memory>

int main()
{
    std::unique_ptr<int[]> intarrayPtr =
        std::make_unique<int[]>(100);

    intarrayPtr[0] = 10;

} // Array is automatically deleted here

Use intarrayPtr.reset() if you want to release the memory before the pointer goes out of scope.

shared_ptr

A shared_ptr is a smart pointer that allows multiple shared_ptr objects to share ownership of the same object. The object is automatically destroyed when the last shared_ptr owning it is destroyed or reset.

The syntax for std::shared_ptr in C++ is:

std::shared_ptr pointerName = std::make_shared(arguments);

shared_ptr uses reference counting to keep track of how many shared_ptr objects currently own the same object. When the reference count reaches zero, the object is automatically destroyed.

#include <iostream>
#include <memory>

int main()
{
    std::shared_ptr<int> ptr1 = std::make_shared<int>(15);
    std::cout << "ptr1 value: " << *ptr1 << '\n';
    std::cout << "Owners: " << ptr1.use_count() << '\n';
    {
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "ptr2 value: " << *ptr2 << '\n';
        std::cout << "Owners: " << ptr1.use_count() << '\n';
        *ptr2 = 25;
        std::cout << "ptr1 value: " << *ptr1 << '\n';
    }

    std::cout << "Owners after ptr2 goes out of scope: "
              << ptr1.use_count() << '\n';
    return 0;
}

Output
ptr1 value: 15
Owners: 1
ptr2 value: 15
Owners: 2
ptr1 value: 25
Owners after ptr2 goes out of scope: 1

How it works

  1. ptr1 owns an integer containing 15.
  2. ptr2 = ptr1 creates a second shared owner of the same integer.
  3. Changing *ptr2 to 25 also changes the value observed through ptr1, because both pointers refer to the same object.
  4. When ptr2 goes out of scope, its ownership is released and the owner count returns to 1.
  5. When ptr1 goes out of scope, the last owner is released and the integer is automatically destroyed.

Key point: Shared ownership means multiple smart pointers can manage the lifetime of the same object. The object remains alive until the last owning std::shared_ptr releases it.

weak_ptr

A std::weak_ptr is a smart pointer that provides non-owning access to an object managed by a std::shared_ptr. It can be created from a std::shared_ptr and does not increase the shared ownership reference count or extend the object’s lifetime.

A std::weak_ptr can be used to check whether the object still exists by calling expired(). Alternatively, lock() returns a std::shared_ptr if the object still exists, or an empty std::shared_ptr if it has already been destroyed.

This is useful when you need to refer to an object without keeping it alive. It can also help prevent circular references between std::shared_ptr objects.

#include <iostream>
#include <memory>

int main()
{
    std::shared_ptr<int> sharedPtr = std::make_shared<int>(100);
    std::weak_ptr<int> weakPtr = sharedPtr;

    std::cout << "Owners: " << sharedPtr.use_count() << '\n';

    if (auto lockedPtr = weakPtr.lock())
    {
        std::cout << "Value: " << *lockedPtr << '\n';
    }

    sharedPtr.reset();

    if (weakPtr.expired())
    {
        std::cout << "Object no longer exists\n";
    }

    return 0;
}

Output:
Owners: 1
Value: 100
Object no longer exists

Explanation:

  • weakPtr refers to the object managed by sharedPtr without owning it.
  • weakPtr.lock() temporarily obtains shared ownership if the object still exists.
  • sharedPtr.reset() releases sharedPtr’s ownership. Once the temporary lockedPtr has gone out of scope, no shared owners remain, so the integer is destroyed.
  • weakPtr.expired() returns true because the object has been destroyed.

In addition to the smart pointers described above, earlier versions of C++ included std::auto_ptr. This smart pointer was deprecated in C++11 because of its problematic ownership behaviour and was removed from the C++17 standard. Modern C++ programs should use std::unique_ptr instead.