Namespaces
Variants

std:: unique_ptr

From cppreference.net
Memory management library
( exposition only* )
Allocators
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Memory resources
Uninitialized storage (until C++20)
( until C++20* )
( until C++20* )
( until C++20* )

Garbage collector support (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
Definido en el encabezado <memory>
template <

class T,
class Deleter = std:: default_delete < T >

> class unique_ptr ;
(1) (desde C++11)
template <

class T,
class Deleter

> class unique_ptr < T [ ] , Deleter > ;
(2) (desde C++11)

std::unique_ptr es un puntero inteligente que posee (es responsable de) y gestiona otro objeto a través de un puntero, y posteriormente elimina ese objeto cuando el unique_ptr sale del ámbito.

El objeto se elimina, utilizando el eliminador asociado, cuando ocurre cualquiera de los siguientes casos:

  • el objeto unique_ptr administrador es destruido.
  • el objeto unique_ptr administrador es asignado a otro puntero mediante operator= o reset() .

El objeto es eliminado, utilizando un eliminador potencialmente suministrado por el usuario, llamando a get_deleter ( ) ( ptr ) . El eliminador por defecto ( std::default_delete ) utiliza el operador delete , que destruye el objeto y desasigna la memoria.

Un unique_ptr puede no poseer ningún objeto, en cuyo caso se describe como vacío .

Hay dos versiones de unique_ptr :

  1. Gestiona un único objeto (por ejemplo, asignado con new ).
  2. Gestiona un array de objetos asignado dinámicamente (por ejemplo, asignado con new [ ] ).

La clase satisface los requisitos de MoveConstructible y MoveAssignable , pero no los de CopyConstructible ni CopyAssignable .

Si T* no era un tipo válido (por ejemplo, T es un tipo de referencia), un programa que instancia la definición de std :: unique_ptr < T, Deleter > está mal formado.

Requisitos de tipo
-
Deleter debe ser FunctionObject o referencia lvalue a un FunctionObject o referencia lvalue a función, invocable con un argumento de tipo unique_ptr < T, Deleter > :: pointer .

Contenidos

Notas

Solo los unique_ptr no constantes pueden transferir la propiedad del objeto gestionado a otro unique_ptr . Si el tiempo de vida de un objeto está gestionado por un const std :: unique_ptr , está limitado al ámbito en el que se creó el puntero.

unique_ptr se utiliza comúnmente para gestionar el ciclo de vida de objetos, incluyendo:

  • proporcionar seguridad de excepciones a clases y funciones que manejan objetos con tiempo de vida dinámico, garantizando la eliminación tanto en la salida normal como en la salida mediante excepción.
  • transferir la propiedad de objetos de propiedad única con tiempo de vida dinámico a funciones.
  • adquiriendo propiedad de objetos de propiedad única con tiempo de vida dinámico desde funciones.
  • como el tipo de elemento en contenedores conscientes del movimiento, tales como std::vector , que mantienen punteros a objetos asignados dinámicamente (por ejemplo, si se desea comportamiento polimórfico).

unique_ptr puede ser construido para un tipo incompleto T , como para facilitar su uso como manejador en el idiom pImpl . Si se utiliza el eliminador por defecto, T debe estar completo en el punto del código donde se invoca el eliminador, lo cual ocurre en el destructor, el operador de asignación de movimiento, y la función miembro reset de unique_ptr . (En contraste, std::shared_ptr no puede ser construido desde un puntero crudo a tipo incompleto, pero puede ser destruido donde T es incompleto). Nótese que si T es una especialización de plantilla de clase, el uso de unique_ptr como operando, ej. ! p requiere que los parámetros de T estén completos debido a ADL .

Si T es una clase derivada de alguna clase base B , entonces unique_ptr < T > es implícitamente convertible a unique_ptr < B > . El eliminador predeterminado del unique_ptr < B > resultante usará operator delete para B , lo que conduce a comportamiento indefinido a menos que el destructor de B sea virtual . Nótese que std::shared_ptr se comporta de forma diferente: std:: shared_ptr < B > usará el operator delete para el tipo T y el objeto poseído será eliminado correctamente incluso si el destructor de B no es virtual .

A diferencia de std::shared_ptr , unique_ptr puede gestionar un objeto a través de cualquier tipo de handle personalizado que satisfaga NullablePointer . Esto permite, por ejemplo, gestionar objetos ubicados en memoria compartida, proporcionando un Deleter que defina typedef boost::offset_ptr pointer; u otro fancy pointer .

Macro de prueba de características Valor Std Característica
__cpp_lib_constexpr_memory 202202L (C++23) constexpr std::unique_ptr

Tipos anidados

Tipo Definición
pointer std:: remove_reference < Deleter > :: type :: pointer si ese tipo existe, de lo contrario T* . Debe satisfacer NullablePointer
element_type T , el tipo del objeto gestionado por este unique_ptr
deleter_type Deleter , el objeto función o referencia lvalue a función o a objeto función, a ser llamado desde el destructor

Funciones miembro

construye un nuevo unique_ptr
(función miembro pública)
destruye el objeto gestionado si existe
(función miembro pública)
asigna el unique_ptr
(función miembro pública)
Modificadores
devuelve un puntero al objeto gestionado y libera la propiedad
(función miembro pública)
reemplaza el objeto gestionado
(función miembro pública)
intercambia los objetos gestionados
(función miembro pública)
Observadores
devuelve un puntero al objeto gestionado
(función miembro pública)
devuelve el deleter utilizado para la destrucción del objeto gestionado
(función miembro pública)
verifica si existe un objeto gestionado asociado
(función miembro pública)
Versión de objeto único, unique_ptr<T>
desreferencia el puntero al objeto gestionado
(función miembro pública)
Versión de array, unique_ptr<T[]>
proporciona acceso indexado al array gestionado
(función miembro pública)

Funciones no miembro

crea un unique pointer que gestiona un nuevo objeto
(plantilla de función)
compara con otro unique_ptr o con nullptr
(plantilla de función)
envía el valor del puntero gestionado a un flujo de salida
(plantilla de función)
especializa el algoritmo std::swap
(plantilla de función)

Clases auxiliares

Soporte de hash para std::unique_ptr
(especialización de plantilla de clase)

Ejemplo

#include <cassert>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <locale>
#include <memory>
#include <stdexcept>
// clase auxiliar para la demostración de polimorfismo en tiempo de ejecución a continuación
struct B
{
    virtual ~B() = default;
    virtual void bar() { std::cout << "B::bar\n"; }
};
struct D : B
{
    D() { std::cout << "D::D\n"; }
    ~D() { std::cout << "D::~D\n"; }
    void bar() override { std::cout << "D::bar\n"; }
};
// una función que consume un unique_ptr puede tomarlo por valor o por referencia de valor derecho
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
    p->bar();
    return p;
}
// función auxiliar para la demostración del eliminador personalizado a continuación
void close_file(std::FILE* fp)
{
    std::fclose(fp);
}
// unique_ptr-based linked list demo
struct List
{
    struct Node
    {
        int data;
        std::unique_ptr<Node> next;
    };
    std::unique_ptr<Node> head;
    ~List()
    {
        // destruir nodos de lista secuencialmente en un bucle, el destructor predeterminado
        // habría invocado el destructor de su "next" recursivamente, lo que
        // causa desbordamiento de pila para listas suficientemente grandes.
        while (head)
        {
            auto next = std::move(head->next);
            head = std::mover(next);
        }
    }
    void push(int data)
    {
        head = std::unique_ptr<Node>(new Node{data, std::move(head)});
    }
};
int main()
{
    std::cout << "1) Demostración de semántica de propiedad única\n";
    {
        // Crear un recurso (de propiedad única)
        std::unique_ptr<D> p = std::make_unique<D>();
        // Transfer ownership to “pass_through”,
        // que a su vez transfiere la propiedad de vuelta a través del valor de retorno
        std::unique_ptr<D> q = pass_through(std::move(p));
        // “p” está ahora en un estado 'vacío' tras ser movido, igual a nullptr
        assert(!p);
    }
    std::cout << "\n" "2) Demostración de polimorfismo en tiempo de ejecución\n";
    {
        // Crear un recurso derivado y apuntar a él mediante el tipo base
        std::unique_ptr<B> p = std::make_unique<D>();
        // Dynamic dispatch funciona como se espera
        p->bar();
    }
    std::cout << "\n" "3) Demostración de eliminador personalizado\n";
    std::ofstream("demo.txt") << 'x'; // preparar el archivo para leer
    {
        using unique_file_t = std::unique_ptr<std::FILE, decltype(&close_file)>;
        unique_file_t fp(std::fopen("demo.txt", "r"), &close_file);
        if (fp)
            std::cout << char(std::fgetc(fp.get())) << '\n';
    } // “close_file()” llamado aquí (si “fp” no es nulo)
    std::cout << "\n" "4) Demostración de eliminador de expresión lambda personalizado y seguridad de excepciones\n";
    try
    {
        std::unique_ptr<D, void(*)(D*)> p(new D, [](D* ptr)
        {
            std::cout << "destruyendo desde un deleter personalizado...\n";
            delete ptr;
        });
        throw std::runtime_error(""); // “p” tendría una fuga de memoria aquí si fuera un puntero simple
    }
    catch (const std::exception&)
    {
        std::cout << "Excepción capturada\n";
    }
    std::cout << "\n" "5) Demostración de unique_ptr en forma de array\n";
    {
        std::unique_ptr<D[]> p(new D[3]);
    } // “D::~D()” is called 3 times
    std::cout << "\n" "6) Demostración de lista enlazada\n";
    {
        List wall;
        const int enough{1'000'000};
        for (int beer = 0; beer != enough; ++beer)
            wall.push(beer);
        std::cout.imbue(std::locale("en_US.UTF-8"));
        std::cout << enough << " botellas de cerveza en la pared...\n";
    } // destruye todas las cervezas
}

Salida posible:

1) Demostración de semántica de propiedad única
D::D
D::bar
D::~D
2) Demostración de polimorfismo en tiempo de ejecución
D::D
D::bar
D::~D
3) Demostración de eliminador personalizado
x
4) Demostración de eliminador con expresión lambda y seguridad ante excepciones
D::D
destruyendo desde un eliminador personalizado...
D::~D
Excepción capturada
5) Demostración de unique_ptr en forma de array
D::D
D::D
D::D
D::~D
D::~D
D::~D
6) Demostración de lista enlazada
1,000,000 botellas de cerveza en la pared...

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.

DR Aplicado a Comportamiento publicado Comportamiento correcto
LWG 4144 C++11 T* no se requería que formara un tipo válido requerido

Véase también

(C++11)
puntero inteligente con semántica de propiedad compartida de objetos
(plantilla de clase)
(C++11)
referencia débil a un objeto gestionado por std::shared_ptr
(plantilla de clase)
(C++26)
un contenedor que contiene un objeto asignado dinámicamente con semántica de valor
(plantilla de clase)
(C++17)
objetos que contienen instancias de cualquier tipo CopyConstructible
(clase)