Clase shared_ptr

Encapsula un puntero inteligente en el que se cuentan las referencias alrededor de un objeto asignado dinámicamente.

Sintaxis

template <class T>
class shared_ptr;

Comentarios

La clase shared_ptr describe un objeto que utiliza el recuento de referencias para administrar recursos. Un objeto shared_ptr contiene eficazmente un puntero al recurso que posee o contiene un puntero null. Un recurso puede ser propiedad de más de un objeto shared_ptr; cuando se destruye el último objeto shared_ptr que posee un recurso determinado, se libera el recurso.

Un shared_ptr deja de ser el propietario de un recurso cuando se reasigna o se restablece.

El argumento de plantilla T puede ser un tipo incompleto, salvo lo indicado para ciertas funciones miembro.

Cuando se construye un objeto shared_ptr<T> desde un puntero de recursos de tipo G* o desde un shared_ptr<G>, el tipo de puntero G* debe poder convertirse a T*. Si no es convertible, el código no se compilará. Por ejemplo:

#include <memory>
using namespace std;

class F {};
class G : public F {};

shared_ptr<G> sp0(new G);   // okay, template parameter G and argument G*
shared_ptr<G> sp1(sp0);     // okay, template parameter G and argument shared_ptr<G>
shared_ptr<F> sp2(new G);   // okay, G* convertible to F*
shared_ptr<F> sp3(sp0);     // okay, template parameter F and argument shared_ptr<G>
shared_ptr<F> sp4(sp2);     // okay, template parameter F and argument shared_ptr<F>
shared_ptr<int> sp5(new G); // error, G* not convertible to int*
shared_ptr<int> sp6(sp2);   // error, template parameter int and argument shared_ptr<F>

Un objeto shared_ptr posee un recurso:

  • si se construyó con un puntero a ese recurso,

  • si se construyó desde un objeto shared_ptr que posee ese recurso,

  • si se construyó desde un objeto weak_ptr que apunta a ese recurso, o

  • si se le asignó la propiedad de ese recurso, ya sea con shared_ptr::operator= o llamando a la función miembro shared_ptr::reset.

Los objetos shared_ptr que poseen un recurso comparten un bloque de control. El bloque de control contiene:

  • el número de objetos shared_ptr que poseen el recurso,

  • el número de objetos weak_ptr que apuntan al recurso,

  • el eliminador para ese recurso, si existe,

  • el asignador personalizado para el bloque de control, si tiene alguno.

Un objeto shared_ptr que se inicializa mediante un puntero nulo tiene un bloque de control y no está vacío. Después de que un objeto shared_ptr libera un recurso, ya no posee ese recurso. Después de que un objeto weak_ptr libera un recurso, ya no apunta a ese recurso.

Cuando el número de objetos shared_ptr que poseen un recurso es cero, el recurso se libera eliminándolo o pasando su dirección a un eliminador, según cómo se creara originalmente la propiedad del recurso. Cuando el número de objetos shared_ptr que poseen un recurso es cero, y el número de objetos weak_ptr que apuntan a ese recurso es cero, el bloque de control se libera, utilizando el asignador personalizado para el bloque de control si tiene alguno.

Un objeto vacío shared_ptr no posee ningún recurso y no tiene ningún bloque de control.

Un eliminador es un objeto de función que tiene una función miembro operator(). Su tipo se debe poder construir mediante copia, y su constructor y destructor de copias no deben producir excepciones. Acepta un parámetro: el objeto que se va a eliminar.

Algunas funciones toman una lista de argumentos que define propiedades del objeto shared_ptr<T> o weak_ptr<T> resultante. Hay varias maneras de especificar esta lista de argumentos:

sin argumentos: el objeto resultante es un objeto vacío shared_ptr o weak_ptr.

ptr: un puntero de tipo Other* al recurso que se va a administrar. T debe ser un tipo completo. Si se produce un error en la función (porque no se puede asignar el bloque de control), evalúa la expresión delete ptr.

ptr, deleter: un puntero de tipo Other* al recurso que se va a administrar y un eliminador para ese recurso. Si se produce un error en la función (porque no se puede asignar el bloque de control), llama a deleter(ptr), que debe estar bien definido.

ptr, deleter, alloc: un puntero de tipo Other* al recurso que se va a administrar, un eliminador para ese recurso y un asignador para administrar cualquier almacenamiento que se deba asignarse y liberarse. Si se produce un error en la función (porque no se puede asignar el bloque de control), llama a deleter(ptr), que debe estar bien definido.

sp: un objeto shared_ptr<Other> que posee el recurso que se va a administrar.

wp: un objeto weak_ptr<Other> que apunta al recurso que se va a administrar.

ap: un objeto auto_ptr<Other> que contiene un puntero al recurso que se va a administrar. Si la función se ejecuta correctamente, llama a ap.release(); de lo contrario, deja ap sin modificar.

En todos los casos, el tipo de puntero Other* debe poder convertirse a T*.

Seguridad para subprocesos

Varios subprocesos pueden leer y escribir diferentes objetos shared_ptr al mismo tiempo, incluso cuando los objetos son copias que comparten la propiedad.

Miembros

Nombre Descripción
Constructores
shared_ptr Construye un objeto shared_ptr.
~shared_ptr Destruye un objeto shared_ptr.
Typedefs
element_type El tipo de un elemento.
weak_type El tipo de un puntero débil a un elemento.
Funciones miembro
get Obtiene la dirección del recurso propio.
owner_before Devuelve true si este shared_ptr está ordenado antes (o es menor que) que el puntero proporcionado.
reset Reemplaza el recurso propio.
swap Intercambia dos objetos shared_ptr.
unique Comprueba si el recurso propio es único.
use_count Cuenta los números de propietarios del recurso.
Operadores
operator bool Comprueba si existe un recurso propio.
operator* Obtiene el valor designado.
operator= Reemplaza el recurso propio.
operator-> Obtiene un puntero al valor designado.

element_type

El tipo de un elemento.

typedef T element_type;                  // before C++17
using element_type = remove_extent_t<T>; // C++17

Comentarios

El tipo element_type es un sinónimo para el parámetro de plantilla T.

Ejemplo

// std__memory__shared_ptr_element_type.cpp
// compile with: /EHsc
#include <memory>
#include <iostream>

int main()
{
    std::shared_ptr<int> sp0(new int(5));
    std::shared_ptr<int>::element_type val = *sp0;

    std::cout << "*sp0 == " << val << std::endl;

    return (0);
}
*sp0 == 5

get

Obtiene la dirección del recurso propio.

element_type* get() const noexcept;

Comentarios

La función miembro devuelve la dirección del recurso propietario. Devuelve 0 si el objeto no dispone de un recurso.

Ejemplo

// std__memory__shared_ptr_get.cpp
// compile with: /EHsc
#include <memory>
#include <iostream>

int main()
{
    std::shared_ptr<int> sp0;
    std::shared_ptr<int> sp1(new int(5));

    std::cout << "sp0.get() == 0 == " << std::boolalpha
        << (sp0.get() == 0) << std::endl;
    std::cout << "*sp1.get() == " << *sp1.get() << std::endl;

    return (0);
}
sp0.get() == 0 == true
*sp1.get() == 5

operator bool

Comprueba si existe un recurso propio.

explicit operator bool() const noexcept;

Comentarios

El operador devuelve un valor de true cuando get() != nullptr, en caso contrario false.

Ejemplo

// std__memory__shared_ptr_operator_bool.cpp
// compile with: /EHsc
#include <memory>
#include <iostream>

int main()
{
    std::shared_ptr<int> sp0;
    std::shared_ptr<int> sp1(new int(5));

    std::cout << "(bool)sp0 == " << std::boolalpha
        << (bool)sp0 << std::endl;
    std::cout << "(bool)sp1 == " << std::boolalpha
        << (bool)sp1 << std::endl;

    return (0);
}
(bool)sp0 == false
(bool)sp1 == true

operator*

Obtiene el valor designado.

T& operator*() const noexcept;

Comentarios

El operador de direccionamiento indirecto devuelve *get(). Por tanto, el puntero almacenado no debe ser nulo.

Ejemplo

// std__memory__shared_ptr_operator_st.cpp
// compile with: /EHsc
#include <memory>
#include <iostream>

int main()
{
    std::shared_ptr<int> sp0(new int(5));

    std::cout << "*sp0 == " << *sp0 << std::endl;

    return (0);
}
*sp0 == 5

operator=

Reemplaza el recurso propio.

shared_ptr& operator=(const shared_ptr& sp) noexcept;

shared_ptr& operator=(shared_ptr&& sp) noexcept;

template <class Other>
shared_ptr& operator=(const shared_ptr<Other>& sp) noexcept;

template <class Other>
shared_ptr& operator=(shared_ptr<Other>&& sp) noexcept;

template <class Other>
shared_ptr& operator=(auto_ptr<Other>&& ap);    // deprecated in C++11, removed in C++17

template <class Other, class Deleter>
shared_ptr& operator=(unique_ptr<Other, Deleter>&& up);

Parámetros

sp
El puntero compartido que se va a copiar o desde el que se va a mover.

ap
El puntero automático que se va a mover. La sobrecarga auto_ptr está en desuso en C++11 y se ha quitado en C++17.

up
El puntero único al objeto del que se va a adoptar la propiedad. up no posee ningún objeto después de la llamada.

Other
El tipo del objeto al que apuntan sp, apo up.

Deleter
Tipo del eliminador del objeto apropiado, almacenado para su eliminación posterior del objeto.

Comentarios

Todos los operadores disminuyen el recuento de referencias para el recurso que posee actualmente *this y asignan la propiedad del recurso denominado por la secuencia de operandos a *this. Si el recuento de referencias llega a cero, se libera el recurso. Si un operador produce errores, deja a *this sin cambios.

Ejemplo

// std__memory__shared_ptr_operator_as.cpp
// compile with: /EHsc
#include <memory>
#include <iostream>

int main()
{
    std::shared_ptr<int> sp0;
    std::shared_ptr<int> sp1(new int(5));
    std::unique_ptr<int> up(new int(10));

    sp0 = sp1;
    std::cout << "*sp0 == " << *sp0 << std::endl;

    sp0 = up;
    std::cout << "*sp0 == " << *sp0 << std::endl;

    return (0);
}
*sp0 == 5
*sp0 == 10

operator->

Obtiene un puntero al valor designado.

T* operator->() const noexcept;

Comentarios

El operador de selección devuelve get(), de modo que la expresión sp->member se comporta igual que (sp.get())->member donde sp es un objeto de clase shared_ptr<T>. Por tanto, el puntero almacenado no debe ser null, y T debe ser una clase, estructura o tipo de unión con un miembro member.

Ejemplo

// std__memory__shared_ptr_operator_ar.cpp
// compile with: /EHsc
#include <memory>
#include <iostream>

typedef std::pair<int, int> Mypair;
int main()
{
    std::shared_ptr<Mypair> sp0(new Mypair(1, 2));

    std::cout << "sp0->first == " << sp0->first << std::endl;
    std::cout << "sp0->second == " << sp0->second << std::endl;

    return (0);
}
sp0->first == 1
sp0->second == 2

owner_before

Devuelve true si este shared_ptr está ordenado antes (o es menor que) que el puntero proporcionado.

template <class Other>
bool owner_before(const shared_ptr<Other>& ptr) const noexcept;

template <class Other>
bool owner_before(const weak_ptr<Other>& ptr) const noexcept;

Parámetros

ptr
Una referencia Ivalue a un shared_ptr o un weak_ptr.

Comentarios

La función miembro de plantilla devuelve true si *this es ordenado antes que ptr.

reset

Reemplaza el recurso propio.

void reset() noexcept;

template <class Other>
void reset(Other *ptr);

template <class Other, class Deleter>
void reset(
    Other *ptr,
    Deleter deleter);

template <class Other, class Deleter, class Allocator>
void reset(
    Other *ptr,
    Deleter deleter,
    Allocator alloc);

Parámetros

Other
Tipo controlado por el puntero de argumento.

Deleter
Tipo del eliminador.

ptr
Puntero que se va a copiar.

deleter
El eliminador que se va a copiar.

Allocator
Tipo del asignador.

alloc
El asignador que se va a copiar.

Comentarios

Todos los operadores disminuyen el recuento de referencias para el recurso que posee actualmente *this y asignan la propiedad del recurso denominado por la secuencia de operandos a *this. Si el recuento de referencias llega a cero, se libera el recurso. Si un operador produce errores, deja a *this sin cambios.

Ejemplo

// std__memory__shared_ptr_reset.cpp
// compile with: /EHsc
#include <memory>
#include <iostream>

struct deleter
{
    void operator()(int *p)
    {
        delete p;
    }
};

int main()
{
    std::shared_ptr<int> sp(new int(5));

    std::cout << "*sp == " << std::boolalpha
        << *sp << std::endl;

    sp.reset();
    std::cout << "(bool)sp == " << std::boolalpha
        << (bool)sp << std::endl;

    sp.reset(new int(10));
    std::cout << "*sp == " << std::boolalpha
        << *sp << std::endl;

    sp.reset(new int(15), deleter());
    std::cout << "*sp == " << std::boolalpha
        << *sp << std::endl;

    return (0);
}
*sp == 5
(bool)sp == false
*sp == 10
*sp == 15

shared_ptr

Construye un objeto shared_ptr.

constexpr shared_ptr() noexcept;

constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() {}

shared_ptr(const shared_ptr& sp) noexcept;

shared_ptr(shared_ptr&& sp) noexcept;

template <class Other>
explicit shared_ptr(Other* ptr);

template <class Other, class Deleter>
shared_ptr(
    Other* ptr,
    Deleter deleter);

template <class Deleter>
shared_ptr(
    nullptr_t ptr,
    Deleter deleter);

template <class Other, class Deleter, class Allocator>
shared_ptr(
    Other* ptr,
    Deleter deleter,
    Allocator alloc);

template <class Deleter, class Allocator>
shared_ptr(
    nullptr_t ptr,
    Deleter deleter,
    Allocator alloc);

template <class Other>
shared_ptr(
    const shared_ptr<Other>& sp) noexcept;

template <class Other>
explicit shared_ptr(
    const weak_ptr<Other>& wp);

template <class &>
shared_ptr(
    std::auto_ptr<Other>& ap);

template <class &>
shared_ptr(
    std::auto_ptr<Other>&& ap);

template <class Other, class Deleter>
shared_ptr(
    unique_ptr<Other, Deleter>&& up);

template <class Other>
shared_ptr(
    const shared_ptr<Other>& sp,
    element_type* ptr) noexcept;

template <class Other>
shared_ptr(
    shared_ptr<Other>&& sp,
    element_type* ptr) noexcept;

template <class Other, class Deleter>
shared_ptr(
    const unique_ptr<Other, Deleter>& up) = delete;

Parámetros

Other
Tipo controlado por el puntero de argumento.

ptr
Puntero que se va a copiar.

Deleter
Tipo del eliminador.

Allocator
Tipo del asignador.

deleter
Eliminador.

alloc
Asignador.

sp
El puntero inteligente que se va a copiar.

wp
El puntero débil.

ap
El puntero automático que se va a copiar.

Comentarios

Los constructores crean un objeto que posee el recurso denominado por la secuencia de operandos. El constructor shared_ptr(const weak_ptr<Other>& wp) inicia un objeto de excepción de tipo bad_weak_ptrsi wp.expired().

Ejemplo

// std__memory__shared_ptr_construct.cpp
// compile with: /EHsc
#include <memory>
#include <iostream>

struct deleter
{
    void operator()(int *p)
    {
        delete p;
    }
};

int main()
{
    std::shared_ptr<int> sp0;
    std::cout << "(bool)sp0 == " << std::boolalpha
        << (bool)sp0 << std::endl;

    std::shared_ptr<int> sp1(new int(5));
    std::cout << "*sp1 == " << *sp1 << std::endl;

    std::shared_ptr<int> sp2(new int(10), deleter());
    std::cout << "*sp2 == " << *sp2 << std::endl;

    std::shared_ptr<int> sp3(sp2);
    std::cout << "*sp3 == " << *sp3 << std::endl;

    std::weak_ptr<int> wp(sp3);
    std::shared_ptr<int> sp4(wp);
    std::cout << "*sp4 == " << *sp4 << std::endl;

    std::auto_ptr<int> ap(new int(15));
    std::shared_ptr<int> sp5(ap);
    std::cout << "*sp5 == " << *sp5 << std::endl;

    return (0);
}
(bool)sp0 == false
*sp1 == 5
*sp2 == 10
*sp3 == 10
*sp4 == 10
*sp5 == 15

~shared_ptr

Destruye un objeto shared_ptr.

~shared_ptr();

Comentarios

El destructor disminuye el recuento de referencias para el recurso que posee actualmente *this. Si el recuento de referencias llega a cero, se libera el recurso.

Ejemplo

// std__memory__shared_ptr_destroy.cpp
// compile with: /EHsc
#include <memory>
#include <iostream>

int main()
{
    std::shared_ptr<int> sp1(new int(5));
    std::cout << "*sp1 == " << *sp1 << std::endl;
    std::cout << "use count == " << sp1.use_count() << std::endl;

    {
        std::shared_ptr<int> sp2(sp1);
        std::cout << "*sp2 == " << *sp2 << std::endl;
        std::cout << "use count == " << sp1.use_count() << std::endl;
    }

    // check use count after sp2 is destroyed
    std::cout << "use count == " << sp1.use_count() << std::endl;

    return (0);
}
*sp1 == 5
use count == 1
*sp2 == 5
use count == 2
use count == 1

swap

Intercambia dos objetos shared_ptr.

void swap(shared_ptr& sp) noexcept;

Parámetros

sp
El puntero compartido que se va a intercambiar.

Comentarios

La función miembro deja el recurso originalmente propiedad de *this para que ahora sea propiedad de sp y el recurso originalmente propiedad de sp para que ahora sea propiedad de *this. La función no modifica los recuentos de referencia para los dos recursos y no inicia ninguna excepción.

Ejemplo

// std__memory__shared_ptr_swap.cpp
// compile with: /EHsc
#include <memory>
#include <iostream>

int main()
{
    std::shared_ptr<int> sp1(new int(5));
    std::shared_ptr<int> sp2(new int(10));
    std::cout << "*sp1 == " << *sp1 << std::endl;

    sp1.swap(sp2);
    std::cout << "*sp1 == " << *sp1 << std::endl;

    swap(sp1, sp2);
    std::cout << "*sp1 == " << *sp1 << std::endl;
    std::cout << std::endl;

    std::weak_ptr<int> wp1(sp1);
    std::weak_ptr<int> wp2(sp2);
    std::cout << "*wp1 == " << *wp1.lock() << std::endl;

    wp1.swap(wp2);
    std::cout << "*wp1 == " << *wp1.lock() << std::endl;

    swap(wp1, wp2);
    std::cout << "*wp1 == " << *wp1.lock() << std::endl;

    return (0);
}
*sp1 == 5
*sp1 == 10
*sp1 == 5
*wp1 == 5
*wp1 == 10
*wp1 == 5

unique

Comprueba si el recurso propio es único. Esta función está en desuso en C++17 y se quitó en C++20.

bool unique() const noexcept;

Comentarios

La función miembro devuelve true si ningún otro objeto shared_ptr posee el recurso que es propiedad de *this, de lo contrario, false.

Ejemplo

// std__memory__shared_ptr_unique.cpp
// compile with: /EHsc
#include <memory>
#include <iostream>

int main()
{
    std::shared_ptr<int> sp1(new int(5));
    std::cout << "sp1.unique() == " << std::boolalpha
        << sp1.unique() << std::endl;

    std::shared_ptr<int> sp2(sp1);
    std::cout << "sp1.unique() == " << std::boolalpha
        << sp1.unique() << std::endl;

    return (0);
}
sp1.unique() == true
sp1.unique() == false

use_count

Cuenta los números de propietarios del recurso.

long use_count() const noexcept;

Comentarios

La función miembro devuelve el número de objetos shared_ptr que poseen el recurso que es propiedad de *this.

Ejemplo

// std__memory__shared_ptr_use_count.cpp
// compile with: /EHsc
#include <memory>
#include <iostream>

int main()
{
    std::shared_ptr<int> sp1(new int(5));
    std::cout << "sp1.use_count() == "
        << sp1.use_count() << std::endl;

    std::shared_ptr<int> sp2(sp1);
    std::cout << "sp1.use_count() == "
        << sp1.use_count() << std::endl;

    return (0);
}
sp1.use_count() == 1
sp1.use_count() == 2

weak_type

El tipo de un puntero débil a un elemento.

using weak_type = weak_ptr<T>; // C++17

Comentarios

La definición weak_type se agregó en C++17.

Consulte también

Referencia de archivos de encabezado
<memory>
unique_ptr
Clase weak_ptr