std::unique_ptr (3) - Linux Manuals

std::unique_ptr: std::unique_ptr

NAME

std::unique_ptr - std::unique_ptr

Synopsis


Defined in header <memory>
template<
class T, (1) (since C++11)
class Deleter = std::default_delete<T>
> class unique_ptr;
template <
class T, (2) (since C++11)
class Deleter
> class unique_ptr<T[], Deleter>;


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.

Type requirements


-
Deleter must be FunctionObject or lvalue reference to a FunctionObject or lvalue reference to function, callable with an argument of type unique_ptr<T, Deleter>::pointer

Notes


Only non-const unique_ptr can transfer the ownership of the managed object to another unique_ptr. If an object's lifetime is managed by a const std::unique_ptr, it is limited to the scope in which the pointer was created.
std::unique_ptr is commonly used to manage the lifetime of objects, including:


* providing exception safety to classes and functions that handle objects with dynamic lifetime, by guaranteeing deletion on both normal exit and exit through exception


* passing ownership of uniquely-owned objects with dynamic lifetime into functions


* acquiring ownership of uniquely-owned objects with dynamic lifetime from functions


* as the element type in move-aware containers, such as std::vector, which hold pointers to dynamically-allocated objects (e.g. if polymorphic behavior is desired)


std::unique_ptr may be constructed for an incomplete_type T, such as to facilitate the use as a handle in the pImpl_idiom. If the default deleter is used, T must be complete at the point in code where the deleter is invoked, which happens in the destructor, move assignment operator, and reset member function of std::unique_ptr. (Conversely, std::shared_ptr can't be constructed from a raw pointer to incomplete type, but can be destroyed where T is incomplete). Note that if T is a class template specialization, use of unique_ptr as an operand, e.g. !p requires T's parameters to be complete due to ADL.
If T is a derived_class of some base B, then std::unique_ptr<T> is implicitly_convertible to std::unique_ptr<B>. The default deleter of the resulting std::unique_ptr<B> will use operator_delete for B, leading to undefined_behavior unless the destructor of B is virtual. Note that std::shared_ptr behaves differently: std::shared_ptr<B> will use the operator_delete for the type T and the owned object will be deleted correctly even if the destructor of B is not virtual.
Unlike std::shared_ptr, std::unique_ptr may manage an object through any custom handle type that satisfies NullablePointer. This allows, for example, managing objects located in shared memory, by supplying a Deleter that defines typedef boost::offset_ptr pointer; or another fancy_pointer.

Member types


Member type Definition
pointer std::remove_reference<Deleter>::type::pointer if that type exists, otherwise T*. Must satisfy NullablePointer
element_type T, the type of the object managed by this unique_ptr
deleter_type Deleter, the function object or lvalue reference to function or to function object, to be called from the destructor

Member functions


              constructs a new unique_ptr
constructor (public member function)
              destructs the managed object if such is present
destructor (public member function)
              assigns the unique_ptr
operator= (public member function)

Modifiers


              returns a pointer to the managed object and releases the ownership
release (public member function)
              replaces the managed object
reset (public member function)
              swaps the managed objects
swap (public member function)

Observers


              returns a pointer to the managed object
get (public member function)
              returns the deleter that is used for destruction of the managed object
get_deleter (public member function)
              checks if there is an associated managed object
operator_bool (public member function)

Single-object version, unique_ptr<T>


              dereferences pointer to the managed object
operator* (public member function)
operator->

Array version, unique_ptr<T[]>


              provides indexed access to the managed array
operator[] (public member function)

Non-member functions


make_unique
make_unique_default_init creates a unique pointer that manages a new object
                           (function template)
(C++14)
(C++20)


operator==
operator!= compares to another unique_ptr or with nullptr
operator< (function template)
operator<=
operator>
operator>=


operator<< outputs the value of the managed pointer to an output stream
                           (function template)
(C++20)


std::swap(std::unique_ptr) specializes the std::swap algorithm
                           (function template)
(C++11)

Helper classes


std::hash<std::unique_ptr> hash support for std::unique_ptr
                           (class template specialization)
(C++11)

Example


// Run this code


  #include <iostream>
  #include <vector>
  #include <memory>
  #include <cstdio>
  #include <fstream>
  #include <cassert>
  #include <functional>


  struct B {
    virtual void bar() { std::cout << "B::bar\n"; }
    virtual ~B() = default;
  };
  struct D : B
  {
      D() { std::cout << "D::D\n"; }
      ~D() { std::cout << "D::~D\n"; }
      void bar() override { std::cout << "D::bar\n"; }
  };


  // a function consuming a unique_ptr can take it by value or by rvalue reference
  std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
  {
      p->bar();
      return p;
  }


  void close_file(std::FILE* fp) { std::fclose(fp); }


  int main()
  {
    std::cout << "unique ownership semantics demo\n";
    {
        auto p = std::make_unique<D>(); // p is a unique_ptr that owns a D
        auto q = pass_through(std::move(p));
        assert(!p); // now p owns nothing and holds a null pointer
        q->bar(); // and q owns the D object
    } // ~D called here


    std::cout << "Runtime polymorphism demo\n";
    {
      std::unique_ptr<B> p = std::make_unique<D>(); // p is a unique_ptr that owns a D
                                                    // as a pointer to base
      p->bar(); // virtual dispatch


      std::vector<std::unique_ptr<B>> v; // unique_ptr can be stored in a container
      v.push_back(std::make_unique<D>());
      v.push_back(std::move(p));
      v.emplace_back(new D);
      for(auto& p: v) p->bar(); // virtual dispatch
    } // ~D called 3 times


    std::cout << "Custom deleter demo\n";
    std::ofstream("demo.txt") << 'x'; // prepare the file to read
    {
        std::unique_ptr<std::FILE, decltype(&close_file)> fp(std::fopen("demo.txt", "r"),
                                                             &close_file);
        if(fp) // fopen could have failed; in which case fp holds a null pointer
          std::cout << (char)std::fgetc(fp.get()) << '\n';
    } // fclose() called here, but only if FILE* is not a null pointer
      // (that is, if fopen succeeded)


    std::cout << "Custom lambda-expression deleter demo\n";
    {
      std::unique_ptr<D, std::function<void(D*)>> p(new D, [](D* ptr)
          {
              std::cout << "destroying from a custom deleter...\n";
              delete ptr;
          }); // p owns D
      p->bar();
    } // the lambda above is called and D is destroyed


    std::cout << "Array form of unique_ptr demo\n";
    {
        std::unique_ptr<D[]> p{new D[3]};
    } // calls ~D 3 times
  }

Output:


  unique ownership semantics demo
  D::D
  D::bar
  D::bar
  D::~D
  Runtime polymorphism demo
  D::D
  D::bar
  D::D
  D::D
  D::bar
  D::bar
  D::bar
  D::~D
  D::~D
  D::~D
  Custom deleter demo
  x
  Custom lambda-expression deleter demo
  D::D
  D::bar
  destroying from a custom deleter...
  D::~D
  Array form of unique_ptr demo
  D::D
  D::D
  D::D
  D::~D
  D::~D
  D::~D