Espacios de nombres
Variantes
Acciones

std::shared_ptr

De cppreference.com
< cpp‎ | memory
 
 
Biblioteca de servicios
 
Gestión de memoria dinámica
Punteros inteligentes
(C++11)
shared_ptr
(C++11)
(C++11)
(hasta C++17)
(C++11)
(C++23)
Asignadores de memoria
Recursos de memoria
Almacenamiento no inicializado
Algoritmos de memoria no inicializada
Algoritmos restringidos de memoria no inicializada
Apoyo para recolección de basura
(C++11)(hasta C++23)
(C++11)(hasta C++23)
(C++11)(hasta C++23)
(C++11)(hasta C++23)
(C++11)(hasta C++23)
(C++11)(hasta C++23)
Misceláneos
(C++20)
(C++11)
(C++11)
 
 
Definido en el archivo de encabezado <memory>
template< class T > class shared_ptr;
(desde C++11)

std::shared_ptr es un puntero inteligente que retiene la posesión compartida de un objeto a través de un puntero. Varios objetos shared_ptr pueden poseer el mismo objeto. El objeto se destruye y su memoria se desasigna cuando sucede uno de lo siguientes:

  • el último shared_ptr restante que posee el objeto se destruye;
  • al último shared_ptr restante que posee el objeto se le asigna otro puntero mediante operator= o reset().

El objeto se destruye usando la expresión-delete o un eliminador personalizado que se suplementa al shared_ptr durante la construcción.

Un shared_ptr puede compartir la posesión de un objeto mientras almacena un puntero a otro objeto. Esta función se puede utilizar para apuntar a objetos miembro mientras se posee el objeto al que pertenecen. El puntero almacenado es al que se accede por get(), los operadores de desreferencia y comparación. El puntero gestionado es el que se pasa al eliminador cuando el recuento de uso llega a cero.

Un shared_ptr también puede no poseer objetos, en cuyo caso se le llama vacío (un shared_ptr vacío puede almacenar un puntero no-nulo si el constructor de alias se utilizó para crearlo).

Todas las especializacines de shared_ptr cumplen con los requerimientos de CopyConstructible, CopyAssignable, y LessThanComparable y son contextualmente convertibles a bool.

Todas las funciones miembro (incluido el constructor de copia y la asignación de copia) pueden invocarse por varios hilos en diferentes instancias de shared_ptr sin sincronización adicional, incluso si estas instancias son copias y comparten la posesión del mismo objeto. Si varios hilos de ejecución acceden a la misma instancia de shared_ptr sin sincronización y cualquiera de esos accesos utiliza una función miembro no constante de shared_ptr, se producirá una carrera de datos; las sobrecargas shared_ptr de funciones atómicas se pueden utilizar para evitar la carrera de datos.

Contenido

[editar] Tipos miembro

Tipo miembro Definición
element_type
T (hasta C++17)
std::remove_extent_t<T> (desde C++17)
weak_type (desde C++17) std::weak_ptr<T>

[editar] Funciones miembro

Construye un nuevo shared_ptr.
(función miembro pública) [editar]
Destruye el objeto poseído si ningún shared_ptr está enlazado a él.
(función miembro pública) [editar]
Asigna el shared_ptr.
(función miembro pública) [editar]
Modificadores
Reemplaza el objeto gestionado.
(función miembro pública) [editar]
Intercambia los objetos gestionados.
(función miembro pública) [editar]
Observadores
Devuelve el puntero almacenado.
(función miembro pública) [editar]
Desreferencia el puntero almacenado.
(función miembro pública) [editar]
Proporciona acceso indexado al array almacenado.
(función miembro pública) [editar]
devuelve el número de objetos shared_ptr que se refieren al mismo objeto gestionado.
(función miembro pública) [editar]
(hasta C++20)
Comprueba si el objeto gestionado se gestiona solo por la instancia de shared_ptr actual.
(función miembro pública) [editar]
Comprueba si el puntero almacenado no es nulo.
(función miembro pública) [editar]
Proporciona un ordenamiento de punteros compartidos basado en propietario.
(función miembro pública) [editar]

[editar] Funciones no miembro

Crea un puntero compartido que gestiona un nuevo objeto.
(plantilla de función) [editar]
Crea un puntero compartido que gestiona un nuevo objeto asignado usando un asignador.
(plantilla de función) [editar]
Aplica static_cast, dynamic_cast, const_cast, o reinterpret_cast al puntero almacenado.
(plantilla de función) [editar]
Devuelve el eliminador del tipo especificado, si se posee.
(plantilla de función) [editar]
(eliminado en C++20)(eliminado en C++20)(eliminado en C++20)(eliminado en C++20)(eliminado en C++20)(C++20)
Se compara con otro

shared_ptr o con nullptr.
(plantilla de función) [editar]

Emite el valor del puntero almacenado a un flujo de salida.
(plantilla de función) [editar]
Especializa el algoritmo std::swap.
(plantilla de función) [editar]
Especializa las operaciones atómicas para std::shared_ptr.
(plantilla de función) [editar]

[editar] Clases auxiliares

Puntero compartido atómico.
(especialización de plantilla de clase) [editar]
Apoyo de generación de dispersión para std::shared_ptr.
(especialización de plantilla de clase) [editar]

[editar] Guías de deducción(desde C++17)

[editar] Notas

La posesión de un objeto solo se puede compartir con otro shared_ptr mediante la construcción por copia o asignando por copia su valor a otro shared_ptr. La construcción de un nuevo shared_ptr usando el puntero sin formato subyacente poseído por otro shared_ptr conduce a un comportamiento no definido.

Un std::shared_ptr puede usarse con un tipo incompleto T. Sin embargo, el constructor a partir de un puntero sin formato (template<class Y> shared_ptr(Y*)) y la función miembro template<class Y> void reset(Y*) solo pueden llamarse con un puntero a un tipo completo (ten en cuenta que std::unique_ptr puede construirse a partir de un puntero sin formato a un tipo incompleto).

El tipo T en std::shared_ptr<T> puede ser un tipo función: en este caso, gestiona un puntero a función, en lugar de un puntero a objeto. Esto a veces se usa para mantener una biblioteca dinámica o un complemento (plug-in) cargado siempre que se haga referencia a cualquiera de sus funciones:

void del(void(*)()) {}
void fun() {}
int main(){
  std::shared_ptr<void()> ee(fun, del);
  (*ee)();
}

[editar] Notas de la implementación

En una implementación típica, shared_ptr mantiene solo dos punteros:

  • el puntero almacenado (el devuelto por get());
  • un puntero a un bloque de control.

El bloque de control es un objeto asignado dinámicamente en memoria que mantiene:

  • o bien un puntero al objeto gestionado o el objeto gestionado mismo;
  • el eliminador (borrado-de-tipo);
  • el asignador (borrado-de-tipo);
  • el número de shared_ptrs que poseen el objeto gestionado;
  • el número de weak_ptrs que se refieren al objeto gestionado.

Cuando se crea un shared_ptr llamando a std::make_shared o std::allocate_shared, la memoria tanto para el bloque de control como para el objeto gestionado se crea con una sola asignación. El objeto gestionado se construye in situ en un dato miembro del bloque de control. Cuando se crea shared_ptr a través de uno de los constructores de shared_ptr, el objeto gestionado y el bloque de control deben asignarse por separado. En este caso, el bloque de control almacena un puntero al objeto gestionado.

El puntero que tiene directamente el shared_ptr es el que devuelve get(), mientras que el puntero u objeto que tiene el bloque de control es el que se eliminará cuando el número de los propietarios compartidos llega a cero. Estos punteros no son necesariamente iguales.

El destructor de shared_ptr decrementa el número de propietarios compartidos del bloque de control. Si ese contador llega a cero, el bloque de control llama al destructor del objeto gestionado. El bloque de control no se desasigna a sí mismo hasta que el contador del std::weak_ptr también llegue a cero.

En las implementaciones existentes, el número de punteros débiles se incrementa ([1], [2]) si existe un puntero compartido al mismo bloque de control.

Para satisfacer los requerimientos de seguridad frente a hilos, los contadores de referencias típicamente se incrementan usando un equivalente de std::atomic::fetch_add con std::memory_order_relaxed (el decremento requiere un ordenamiento más fuerte para destruir de manera segura el bloque de control).

[editar] Ejemplo

#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>
 
struct Base
{
    Base() { std::cout << "  Base::Base()\n"; }
    // Nota: aquí el destructor no virtual está bien
    ~Base() { std::cout << "  Base::~Base()\n"; }
};
 
struct Derivada: public Base
{
    Derivada() { std::cout << "  Derivada::Derivada()\n"; }
    ~Derivada() { std::cout << "  Derivada::~Derivada()\n"; }
};
 
void thr(std::shared_ptr<Base> p)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::shared_ptr<Base> lp = p; // seguro frente a hilos, incluso cuando la
                                  // cuenta de uso, use_count, se incrementa
    {
        static std::mutex io_mutex;
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << "puntero local en un hilo:\n"
                  << "  lp.get() = " << lp.get()
                  << ", lp.use_count() = " << lp.use_count() << '\n';
    }
}
 
int main()
{
    std::shared_ptr<Base> p = std::make_shared<Derivada>();
 
    std::cout << "Se creó Derivada compartida (como un puntero a Base)\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    std::thread t1(thr, p), t2(thr, p), t3(thr, p);
    p.reset(); // liberar posesión desde  main
    std::cout << "Propiedad compartida entre tres hilos y liberada\n"
              << "posesión desde main:\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    t1.join(); t2.join(); t3.join();
    std::cout << "Todos los hilos se completaron, el último liberó a Derivada\n";
}

Posible salida:

Base::Base()
  Derivada::Derivada()
Se creó Derivada compartida (como un puntero a Base)
  p.get() = 0x2299b30, p.use_count() = 1
Propiedad compartida entre tres hilos y liberada
posesión desde main:
  p.get() = 0, p.use_count() = 0
puntero local en un hilo:
  lp.get() = 0x2299b30, lp.use_count() = 5
puntero local en un hilo:
  lp.get() = 0x2299b30, lp.use_count() = 3
puntero local en un hilo:
  lp.get() = 0x2299b30, lp.use_count() = 2
  Derivada::~Derivada()
  Base::~Base()
Todos los hilos se completaron, el último liberó a Derivada

[editar] Véase también

Puntero inteligente con semántica de posesión de objeto única.
(plantilla de clase) [editar]
(C++11)
Referencia débil a un objeto gestionado por std::shared_ptr.
(plantilla de clase) [editar]