shared_ptr, unique_ptr and weak_ptr are three useful smart pointers that holds a reference which will help us managing our pointers easier.

Definition of std::shared_ptr

TL;DR: std::shared_ptr is a pointer agent, which contains one real pointer inside. This agent could be safely copied here and there into a lot of pieces in multiple threads, and automatically destroy the real pointer when the last agent is destroyed.

std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer. Several shared_ptr objects may own the same object. The object is destroyed and its memory deallocated when either of the following happens:

  • the last remaining shared_ptr owning the object is destroyed;
  • the last remaining shared_ptr owning the object is assigned another pointer via operator= or reset().

The object is destroyed using delete-expression or a custom deleter that is supplied to shared_ptr during construction.

A shared_ptr can share ownership of an object while storing a pointer to another object. This feature can be used to point to member objects while owning the object they belong to. The stored pointer is the one accessed by get(), the dereference and the comparison operators. The managed pointer is the one passed to the deleter when use count reaches zero.

A shared_ptr may also own no objects, in which case it is called empty (an empty shared_ptr may have a non-null stored pointer if the aliasing constructor was used to create it).

All specializations of shared_ptr meet the requirements of CopyConstructible, CopyAssignable, and LessThanComparable and are contextually convertible to bool.

All member functions (including copy constructor and copy assignment) can be called by multiple threads on different instances of shared_ptr without additional synchronization even if these instances are copies and share ownership of the same object. If multiple threads of execution access the same shared_ptr without synchronization and any of those accesses uses a non-const member function of shared_ptr then a data race will occur; the shared_ptr overloads of atomic functions can be used to prevent the data race.

Definition of std::unique_ptr

TL;DR: std::unique_ptr is a pointer agent, which contains one real pointer inside. This agent could only be moved(1, 2), but not able to copied(1, 2). Only the last agent could access the real pointer, the pointer will be destroyed when this agent is destroyed (include deleting, out of scope... etc.) e.g.

std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope.

The object is disposed of using the associated deleter when either of the following happens:

  • the managing unique_ptr object is destroyed
  • the managing unique_ptr object is assigned another pointer via operator= or reset().

The object is disposed of using a potentially user-supplied deleter by calling get_deleter()(ptr). The default deleter uses the delete operator, which destroys the object and deallocates the memory.

A unique_ptr may alternatively own no object, in which case it is called empty.

There are two versions of std::unique_ptr:

  • 1) Manages a single object (e.g. allocated with new)
  • 2) Manages a dynamically-allocated array of objects (e.g. allocated with new[])

The class satisfies the requirements of MoveConstructible and MoveAssignable, but not the requirements of either CopyConstructible or CopyAssignable.

Definition of std::weak_ptr

std::weak_ptr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by std::shared_ptr. It must be converted to std::shared_ptr in order to access the referenced object.

std::weak_ptr models temporary ownership: when an object needs to be accessed only if it exists, and it may be deleted at any time by someone else, std::weak_ptr is used to track the object, and it is converted to std::shared_ptr to assume temporary ownership. If the original std::shared_ptr is destroyed at this time, the object's lifetime is extended until the temporary std::shared_ptr is destroyed as well.

In addition, std::weak_ptr is used to break circular references of std::shared_ptr.

#include <iostream>
#include <memory>

void observe(std::weak_ptr<int> gw) {
  std::cout << "use_count == " << gw.use_count() << ": ";
  if (auto spt =
          gw.lock()) {  // Has to be copied into a shared_ptr before usage
    std::cout << *spt << "\n";
  } else {
    std::cout << "gw is expired\n";
  }
}

int main() {
  std::weak_ptr<int> gw;
  {
    std::shared_ptr<int> sp = std::make_shared<int>(42);
    gw = sp;
    observe(gw);
  }

  observe(gw);
}

Output:

use_count == 1: 42
use_count == 0: gw is expired

TODO: Detail comparison and some usage

Categories: Code

Yu

Ideals are like the stars: we never reach them, but like the mariners of the sea, we chart our course by them.

Leave a Reply

Your email address will not be published. Required fields are marked *