C++ Propiedad única (std :: unique_ptr)


Ejemplo

C ++ 11

A std::unique_ptr es una plantilla de clase que administra la vida útil de un objeto almacenado dinámicamente. A diferencia de std::shared_ptr , el objeto dinámico es propiedad de solo una instancia de std::unique_ptr en cualquier momento,


// Creates a dynamic int with value of 20 owned by a unique pointer
std::unique_ptr<int> ptr = std::make_unique<int>(20);

(Nota: std::unique_ptr está disponible desde C ++ 11 y std::make_unique desde C ++ 14).

Sólo la variable ptr mantiene un puntero a un int asignado dinámicamente. Cuando un puntero único que posee un objeto queda fuera del alcance, el objeto propio se elimina, es decir, se llama a su destructor si el objeto es de clase y se libera la memoria para ese objeto.

Para usar std::unique_ptr y std::make_unique con tipos de matriz, use sus especializaciones de matriz:

// Creates a unique_ptr to an int with value 59
std::unique_ptr<int> ptr = std::make_unique<int>(59);

// Creates a unique_ptr to an array of 15 ints
std::unique_ptr<int[]> ptr = std::make_unique<int[]>(15);

Puede acceder a std::unique_ptr como un puntero en bruto, ya que sobrecarga a esos operadores.


Puede transferir la propiedad del contenido de un puntero inteligente a otro puntero utilizando std::move , lo que hará que el puntero inteligente original apunte a nullptr .

// 1. std::unique_ptr
std::unique_ptr<int> ptr = std::make_unique<int>();

// Change value to 1
*ptr = 1;

// 2. std::unique_ptr (by moving 'ptr' to 'ptr2', 'ptr' doesn't own the object anymore)
std::unique_ptr<int> ptr2 = std::move(ptr);

int a = *ptr2; // 'a' is 1
int b = *ptr;  // undefined behavior! 'ptr' is 'nullptr'
               // (because of the move command above)

Pasando unique_ptr a funciones como parámetro:

void foo(std::unique_ptr<int> ptr)
{
    // Your code goes here
}

std::unique_ptr<int> ptr = std::make_unique<int>(59);
foo(std::move(ptr))

Devolviendo unique_ptr desde funciones. Esta es la forma preferida de C ++ 11 de escribir funciones de fábrica, ya que transmite claramente la semántica de propiedad de la devolución: la persona que llama posee el unique_ptr resultante y es responsable de ello.

std::unique_ptr<int> foo()
{
    std::unique_ptr<int> ptr = std::make_unique<int>(59);
    return ptr;
}

std::unique_ptr<int> ptr = foo();

Compara esto con:

int* foo_cpp03();

int* p = foo_cpp03(); // do I own p? do I have to delete it at some point?
                      // it's not readily apparent what the answer is.
C ++ 14

La plantilla de clase make_unique se proporciona desde C ++ 14. Es fácil agregarlo manualmente al código C ++ 11:

template<typename T, typename... Args>
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
make_unique(Args&&... args)
{ return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); }

// Use make_unique for arrays
template<typename T>
typename std::enable_if<std::is_array<T>::value, std::unique_ptr<T>>::type
make_unique(size_t n)
{ return std::unique_ptr<T>(new typename std::remove_extent<T>::type[n]()); }
C ++ 11

A diferencia del puntero inteligente tonto ( std::auto_ptr ), unique_ptr también se puede crear una instancia con asignación de vectores ( no std::vector ). Los ejemplos anteriores fueron para asignaciones escalares . Por ejemplo, para tener una matriz de enteros asignada dinámicamente para 10 elementos, debe especificar int[] como tipo de plantilla (y no solo int ):

std::unique_ptr<int[]> arr_ptr = std::make_unique<int[]>(10);

Que se puede simplificar con:

auto arr_ptr = std::make_unique<int[]>(10);

Ahora, usas arr_ptr como si fuera una matriz:

arr_ptr[2] =  10; // Modify third element

No tiene que preocuparse por la desasignación. Esta plantilla especializada de la versión llama a los constructores y destructores adecuadamente. El uso de la versión vectorizada de unique_ptr o un vector sí mismo es una opción personal.

En versiones anteriores a C ++ 11, std::auto_ptr estaba disponible. A diferencia de unique_ptr , se permite copiar auto_ptr s, sobre el cual la fuente ptr perderá la propiedad del puntero contenido y el destino lo recibirá.