Espacios de nombres
Variantes

std::shared_ptr<T>::shared_ptr

De cppreference.com
 
 
Biblioteca de servicios
 
Gestión de memoria dinámica
Punteros inteligentes
(C++11)
(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)
 
 
<tbody> </tbody>
constexpr shared_ptr() noexcept;
(1)
constexpr shared_ptr( std::nullptr_t ) noexcept;
(2)
template< class Y > explicit shared_ptr( Y* ptr );
(3)
template< class Y, class Deleter > shared_ptr( Y* ptr, Deleter d );
(4)
template< class Deleter > shared_ptr( std::nullptr_t ptr, Deleter d );
(5)
template< class Y, class Deleter, class Alloc > shared_ptr( Y* ptr, Deleter d, Alloc alloc );
(6)
template< class Deleter, class Alloc > shared_ptr( std::nullptr_t ptr, Deleter d, Alloc alloc );
(7)
template< class Y > shared_ptr( const shared_ptr<Y>& r, element_type* ptr ) noexcept;
(8)
template< class Y > shared_ptr( shared_ptr<Y>&& r, element_type* ptr ) noexcept;
(8) (desde C++20)
shared_ptr( const shared_ptr& r ) noexcept;
(9)
template< class Y > shared_ptr( const shared_ptr<Y>& r ) noexcept;
(9)
shared_ptr( shared_ptr&& r ) noexcept;
(10)
template< class Y > shared_ptr( shared_ptr<Y>&& r ) noexcept;
(10)
template< class Y > explicit shared_ptr( const std::weak_ptr<Y>& r );
(11)
template< class Y > shared_ptr( std::auto_ptr<Y>&& r );
(12) (eliminado en C++17)
template< class Y, class Deleter > shared_ptr( std::unique_ptr<Y, Deleter>&& r );
(13)

Construye un nuevo shared_ptr a partir de una variedad de tipos de punteros que se refieren a un objeto a gestionar.

A los efectos de la siguiente descripción, se dice que un puntero de tipo Y* es compatible con un puntero de tipo T* si Y* es convertible a T* o Y es un tipo array U[N] y T es U cv [] (donde cv es algún conjunto de calificadores-cv).

(desde C++17)
1-2) Construye un shared_ptr sin un objeto gestionado. Es decir, un shared_ptr vacío.
3-7) Construye un shared_ptr con ptr como el puntero al objeto gestionado.

Para (3-4,6), Y* debe ser convertible a T*.

(hasta C++17)

Si T es un tipo array U[N], (3-4,6) no participan en la resolución de sobrecarga si Y(*)[N] no es convertible a T*. Si T es un tipo array U[], (3-4,6) no participan en la resolución de sobrecarga si Y(*)[] no es convertible a T*. De lo contrario, (3-4,6) no participan en la resolución de sobrecarga si Y* no es convertible a T*.

(desde C++17)
Además:
3) Usa la expresión delete delete ptr si T no es un tipo array; delete[] ptr si T es un tipo array (desde C++17) como el eliminador. Y debe ser un tipo completo. La expresión delete debe estar bien formada, tener un comportamiento bien definido y no lanzar ninguna excepción. Este constructor tampoco participa en la resolución de sobrecarga si la expresión delete no está bien formada. (desde C++17)
4-5) Usa el eliminador especificado d como el eliminador. La expresión d(ptr) debe estar bien formada, tener un comportamiento bien definido y no lanzar ninguna excepción. La construcción de d y del eliminador almacenado de d no deben lanzar excepciones.

Deleter debe ser CopyConstructible.

(hasta C++17)

Además, estos constructores no participan en la resolución de sobrecarga si la expresión d(ptr) no está bien formada, o si std::is_move_constructible<D>::value es false.

(desde C++17)
6-7) Igual que (4-5), pero además usa una copia de alloc para la asignación de datos para uso interno. Alloc debe ser un Allocator.
8) El constructor de alias: construye un shared_ptr que comparte información de posesión con el valor inicial de r, pero mantiene un puntero no relacionado y no gestionado ptr. Si este shared_ptr es el último del grupo en salir de ámbito, llamará al eliminador almacenado para el objeto gestionado originalmente por r. Sin embargo, llamar a get() en este shared_ptr siempre devolverá una copia de ptr. Es responsabilidad del programador asegurarse de que este ptr siga siendo válido mientras exista este shared_ptr, como en los casos de uso típicos donde ptr es un miembro del objeto administrado por r o es un alias (p. ej., downcast) de r.get() Para la segunda sobrecarga que toma un r-valor, r está vacío y r.get() == nullptr después de la llamada. (desde C++20)
9) Construye un shared_ptr que comparte posesión del objeto gestionado por r. Si r no gestiona ningún objeto, *this tampoco gestiona ningún objeto. La sobrecarga de plantilla no participa en la resolución de sobrecarga si Y* no es implícitamente convertible a (hasta C++17)compatible con (desde C++17) T*.
10) Construye por movimiento un shared_ptr a partir de r. Después de la construcción, *this contiene una copia del estado anterior de r, r está vacío y su puntero almacenado es nulo. La sobrecarga de plantilla no participa en la resolución de sobrecarga si Y* no es implícitamente convertible a (hasta C++17)compatible con (desde C++17) T*.
11) Construye un shared_ptr que comparte posesión del objeto gestionado por r. Y* debe ser implícitamente convertible a T*. (hasta C++17)Esta sobrecarga solo participa en la resolución de sobrecargas si Y* es compatible con T*. (desde C++17) Observa que r.lock() puede usarse para el mismo propósito: la diferencia es que este constructor lanza una excepción si el argumento está vacío, mientras que std::weak_ptr<T>::lock() construye un std::shared_ptr vacío en ese caso.
12) Construye un shared_ptr que almacena y posee el objeto que anteriormente era posesión de r. Y* debe ser convertible a T*. Después de la construcción, r está vacío.
13) Construye un shared_ptr que gestiona el objeto actualmente gestionado por r. El eliminador asociado con r se almacena para la eliminación futura del objeto gestionado. r no gestiona ningún objeto después de la llamada.
Esta sobrecarga no participa en la resolución de sobrecarga si std::unique_ptr<Y, Deleter>::pointer no es compatible con T*. Si r.get() es un puntero nulo, esta sobrecarga es equivalente al constructor por defecto (1). (desde C++17)
Si Deleter es un tipo referencia, es equivalente a shared_ptr(r.release(), std::ref(r.get_deleter()). De lo contrario, es equivalente a shared_ptr(r.release(), std::move(r.get_deleter()))

Cuando T no es un tipo array, las sobrecargas (3), (4) y (6) habilitan shared_from_this con ptr, y la sobrecarga (13) habilita shared_from_this con el puntero devuelto por r.release().

Parámetros

ptr - Un puntero al objeto a gestionar.
d - Un eliminador a usar para destruir el objeto.
alloc - Un asignador de memoria a usar para las asignaciones de datos para uso interno.
r - Otro puntero inteligente con el que compartir la posesión o del que adquirir la posesión.

Excepciones

3) std::bad_alloc si no se pudo obtener la memoria adicional requerida. Puede lanzar una excepción definida por la implementación para otros errores. Si ocurre una excepción, esto llama a delete ptr si T no es un tipo array, y llama a delete[] ptr de lo contrario (desde C++17).
4-7) std::bad_alloc si no se pudo obtener la memoria adicional requerida. Puede lanzar una excepción definida por la implementación para otros errores. Se llama a d(ptr) si ocurre una excepción.
11) std::bad_weak_ptr si r.expired() == true. El constructor no tiene efecto en este caso.
12) std::bad_alloc si no se pudo obtener la memoria adicional requerida. Puede lanzar una excepción definida por la implementación para otros errores. Este constructor no tiene efecto si ocurre una excepción.
13) Si se lanza una excepción, el constructor no tiene efecto.

Notas

Cuando se dice que un constructor habilita shared_from_this con un puntero ptr de tipo U*, significa que determina si U tiene una clase base no ambigua y accesible (desde C++17) que es una especialización de std::enable_shared_from_this, y si es así, el constructor evalúa la declaración:

if (ptr != nullptr && ptr->weak_this.expired())
  ptr->weak_this = std::shared_ptr<std::remove_cv_t<U>>(*this,
                                  const_cast<std::remove_cv_t<U>*>(ptr));

Donde weak_this es el miembro std::weak_ptr mutable oculto de std::enable_shared_from_this. La asignación al miembro weak_this no es atómica y entra en conflicto con cualquier acceso potencialmente concurrente al mismo objeto. Esto garantiza que las llamadas futuras a shared_from_this() compartirán la posesión con el std::shared_ptr creado por este constructor de puntero sin formato.

La prueba ptr->weak_this.expired() en el código de exposición anterior asegura que weak_this no se reasigna si ya indica un propietario. Esta prueba es necesaria a partir de C++17.

Las sobrecargas de puntero sin formato asumen la posesión del objeto apuntado. Por lo tanto, construir un shared_ptr utilizando la sobrecarga de puntero sin formato para un objeto que ya está gestionado por un shared_ptr, como por shared_ptr(ptr.get()) es probable que conduzca a un comportamiento no definido, incluso si el objeto es de un tipo derivado de std::enable_shared_from_this.

Debido a que el constructor por defecto es constexpr, los shared_ptr estáticos se inicializan como parte de la inicialización estática no local, antes de que comience cualquier inicialización dinámica no local. Esto hace que sea seguro usar shared_ptr en un constructor de cualquier objeto estático.

En C++11 y C++14 es válido construir un std::shared_ptr<T> a partir de un std::unique_ptr<T[]>:

std::unique_ptr<int[]> arr(new int[1]);
std::shared_ptr<int> ptr(std::move(arr));

Dado que shared_ptr obtiene su eliminador (un objeto std::default_delete<T[]>) de std::unique_ptr, el array se desasignará correctamente.

Esto ya no está permitido en C++17. En su lugar, se debe usar la forma de array std::shared_ptr<T[]>.

Ejemplo

#include <memory>
#include <iostream>

struct Foo {
    int id{0};
    Foo(int i = 0) : id{i} { std::cout << "Foo::Foo(" << i <<  ")\n"; }
    ~Foo() { std::cout << "Foo::~Foo(), id=" << id << '\n'; }
};

struct D {
    void operator()(Foo* p) const {
        std::cout << "Llamar a delete desde el objeto función. Foo::id=" << p->id << '\n';
        delete p;
    }
};

int main()
{
    {
        std::cout << "1) constructor sin un objeto gestionado\n";
        std::shared_ptr<Foo> sh1;
    }

    {
        std::cout << "2) constructor con objeto\n";
        std::shared_ptr<Foo> sh2(new Foo{10});
        std::cout << "sh2.use_count(): " << sh2.use_count() << '\n';
        std::shared_ptr<Foo> sh3(sh2);
        std::cout << "sh2.use_count(): " << sh2.use_count() << '\n';
        std::cout << "sh3.use_count(): " << sh3.use_count() << '\n';
    }

    {
        std::cout << "3) constructor con objeto y eliminador\n";
        std::shared_ptr<Foo> sh4(new Foo{11}, D());
        std::shared_ptr<Foo> sh5(new Foo{12}, [](auto p) {
           std::cout << "Llamar a delete desde una lambda... p->id=" << p->id << "\n";
           delete p;
        });
    }
}

Salida:

1) constructor sin un objeto gestionado
2) constructor con objeto
Foo::Foo(10)
sh2.use_count(): 1
sh2.use_count(): 2
sh3.use_count(): 2
Foo::~Foo(), id=10
3) constructor con objeto y eliminador
Foo::Foo(11)
Foo::Foo(12)
Llamar a delete desde una lambda... p->id=12
Foo::~Foo(), id=12
Llamar a delete desde el objeto función. Foo::id=11
Foo::~Foo(), id=11

Informes de defectos

Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.

ID Aplicado a Comportamiento según lo publicado Comportamiento correcto
LWG 3548 C++11 El constructor de unique_ptr construía el eliminador por copia En su lugar lo construye por movimiento

Véase también

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]
Permite a un objeto crear un puntero compartido (shared_ptr) refiriéndose a sí mismo.
(plantilla de clase) [editar]