Espacios de nombres
Variantes
Acciones

std::make_shared, std::make_shared_for_overwrite

De cppreference.com
< cpp‎ | memory‎ | shared ptr
 
 
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)
 
 
Definido en el archivo de encabezado <memory>
template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );
(1) (desde C++11)
(T es no array)
template< class T >
shared_ptr<T> make_shared( std::size_t N );
(2) (desde C++20)
(T es U[])
template< class T >
shared_ptr<T> make_shared();
(3) (desde C++20)
(T es U[N])
template< class T >
shared_ptr<T> make_shared( std::size_t N, const std::remove_extent_t<T>& u );
(4) (desde C++20)
(T es U[])
template< class T >
shared_ptr<T> make_shared( const std::remove_extent_t<T>& u );
(5) (desde C++20)
(T es U[N])
template< class T >
shared_ptr<T> make_shared_for_overwrite();
(6) (desde C++20)
(T es not U[])
template< class T >
shared_ptr<T> make_shared_for_overwrite( std::size_t N );
(7) (desde C++20)
(T es U[])
1) Construye un objeto de tipo T y lo envuelve en un std::shared_ptr usando args como la lista de parámetros para el constructor de T. El objeto se construye como si fuera por la expresión ::new (pv) T(std::forward<Args>(args)...), donde pv es un puntero interno void* al almacenamiento adecuado para contener un objeto de tipo T. El almacenamiento suele ser más grande que sizeof(T) para usar una asignación tanto para el bloque de control del puntero compartido como para el objeto T. El constructor std::shared_ptr llamado por esta función habilita shared_from_this con un puntero al objeto recién construido de tipo T.

Esta sobrecarga solo participa en la resolución de sobrecargas si T no es un tipo array.

(desde C++20)
2,3) Igual que (1), pero el objeto construido es un array posiblemente multidimensional cuyos elementos que no son de tipo array de tipo std::remove_all_extents_t<T> se inicializan como si fuera por la expresión new de ubicación ::new(pv) std::remove_all_extents_t<T>(). La sobrecarga (2) crea un array de tamaño N a lo largo de su primera dimensión. Los elementos del array se inicializan en orden ascendente de sus direcciones y, cuando finaliza su tiempo de vida, se destruyen en el orden inverso al de su construcción original.
4,5) Igual que (2,3), pero los elementos del array se inicializan a partir del valor por defecto u. Si U no es un tipo array, entonces esto se realiza como si fuera por la misma expresión new de ubicación que en (1); de lo contrario, esto se realiza como si se inicializaran todos los elementos que no son de tipo array del array (posiblemente multidimensional) con el elemento correspondiente de u con la misma expresión new de ubicación que en (1). La sobrecarga (4) crea un array de tamaño N a lo largo de su primera dimensión. Los elementos del array se inicializan en orden ascendente de sus direcciones y, cuando finaliza su tiempo de vida, se destruyen en el orden inverso al de su construcción original.
6) Igual que (1) si T no es un tipo array y (3) si T es U[N], excepto que el objeto creado es inicializado por defecto.
7) Igual que (2), excepto que los elementos individuales del array son inicializados por defecto.

En cada caso, el objeto (o elementos individuales si T es un tipo array) (desde C++20) se destruirá por p->~X(), donde p es un puntero al objeto y X es su tipo.

Contenido

[editar] Parámetros

args - Lista de argumentos con los que se construirá una instancia de T.
N - Tamaño de array a usar.
u - El valor inicial con el que inicializar cada elemento del array.

[editar] Valor de retorno

std::shared_ptr de una instancia de tipo T.

[editar] Excepciones

Puede lanzar std::bad_alloc o cualquier excepción lanzada por el constructor de T. Si se lanza una excepción, las funciones no tienen efecto. Si se lanza una excepción durante la construcción de del array, los elementos ya inicializados se destruyen en orden inverso. (desde C++20)

[editar] Notas

Esta función se puede utilizar como alternativa a std::shared_ptr<T>(new T(args...)). Las compensaciones son:

  • std::shared_ptr<T>(new T(args...)) realiza al menos dos asignaciones de memoria (uno para el objeto T y otra para el bloque de control del puntero compartido), mientras que std::make_shared<T> generalmente realiza solo una asignación (el estándar recomienda, pero no requiere esto; todas las implementaciones conocidas hacen esto).
  • Si algún std::weak_ptr hace referencia al bloque de control creado por std::make_shared después de que finalizó el tiempo de vida de todos los propietarios compartidos, la memoria ocupada por T persiste hasta todos los propietarios débiles también son destruidos, lo que puede ser indeseable si sizeof(T) es grande.
  • std::shared_ptr<T>(new T(args...)) puede llamar a un constructor no público de T si se ejecuta en un contexto donde es accesible, mientras que std::make_shared requiere acceso público al constructor seleccionado.
  • A diferencia de los constructores de std::shared_ptr, std::make_shared no permite un eliminador personalizado.
  • std::make_shared usa ::new, por lo que si se ha configurado algún comportamiento especial usando un operator new específico de la clase, diferirá de std::shared_ptr<T>(new T(args...)).
(hasta C++20)
  • código como f(std::shared_ptr<int>(new int(42)), g()) puede causar una fuga de memoria si se llama a g después de new int(42) y lanza una excepción, mientras que f(std::make_shared<int>(42), g()) es seguro, ya que nunca se intercalan dos llamadas de función.
(hasta C++17)

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.


Macro de Prueba de característica
__cpp_lib_shared_ptr_arrays
(para las sobrecargas (2-5))


Macro de Prueba de característica
__cpp_lib_smart_ptr_for_overwrite
(para las sobrecargas (6,7))

[editar] Ejemplo

#include <memory>
#include <vector>
#include <iostream>
#include <type_traits>
 
struct C
{
    // constructores necesarios (hasta C++20)
    C(int i) : i(i) {}
    C(int i, float f) : i(i), f(f) {}
    int i;
    float f{};
};
 
int main()
{
    // usando `auto` para el tipo de `sp1`
    auto sp1 = std::make_shared<C>(1); // sobrecarga (1)
    static_assert(std::is_same_v<decltype(sp1), std::shared_ptr<C>>);
    std::cout << "sp1->{ i:" << sp1->i << ", f:" << sp1->f << " }\n";
 
    // siendo explícito con el tipo de `sp2`
    std::shared_ptr<C> sp2 = std::make_shared<C>(2, 3.0f); // sobrecarga (1)
    static_assert(std::is_same_v<decltype(sp2), std::shared_ptr<C>>);
    static_assert(std::is_same_v<decltype(sp1), decltype(sp2)>);
    std::cout << "sp2->{ i:" << sp2->i << ", f:" << sp2->f << " }\n";
 
 
    // véase https://wandbox.org/permlink/wVZT5Gl2omZrhxte
 
    // shared_ptr a un float[64] inicializado por valor; sobrecarga (2):
    std::shared_ptr<float[]> sp3 = std::make_shared<float[]>(64);
 
    // shared_ptr a un long[5][3][4] inicializado por valor; sobrecarga (2):
    std::shared_ptr<long[][3][4]> sp4 = std::make_shared<long[][3][4]>(5);
 
    // shared_ptr a un short[128] inicializado por valor; sobrecarga (3):
    std::shared_ptr<short[128]> sp5 = std::make_shared<short[128]>();
 
    // shared_ptr a un int[7][6][5] inicializado por valor; sobrecarga (3):
    std::shared_ptr<int[7][6][5]> sp6 = std::make_shared<int[7][6][5]>();
 
    // shared_ptr a un double[256], donde cada elemento es 2.0; sobrecarga (4):
    std::shared_ptr<double[]> sp7 = std::make_shared<double[]>(256, 2.0);
 
    // shared_ptr a un double[7][2], donde cada elemento double[2] es {3.0, 4.0}; sobrecarga (4):
    std::shared_ptr<double[][2]> sp8 = std::make_shared<double[][2]>(7, {3.0, 4.0});
 
    // shared_ptr a un vector<int>[4], donde cada vector tiene el contenido {5, 6}; sobrecarga (4):
    std::shared_ptr<std::vector<int>[]> sp9 = std::make_shared<std::vector<int>[]>(4, {5, 6});
 
    // shared_ptr a un float[512], donde cada elemento es 1.0; sobrecarga (5):
    std::shared_ptr<float[512]> spA = std::make_shared<float[512]>(1.0);
 
    // shared_ptr a un double[6][2], donde cada elemento double[2] es {1.0, 2.0}; sobrecarga (5):
    std::shared_ptr<double[6][2]> spB = std::make_shared<double[6][2]>({1.0, 2.0});
 
    // shared_ptr a un vector<int>[4], donde cada vector tiene el contenido {5, 6}; sobrecarga (5):
    std::shared_ptr<std::vector<int>[4]> spC = std::make_shared<std::vector<int>[4]>({5, 6});
}

Salida:

sp1->{ i:1, f:0 }
sp2->{ i:2, f:3 }

[editar] Véase también

Construye un nuevo shared_ptr.
(función miembro pública) [editar]
Crea un puntero compartido que gestiona un nuevo objeto asignado usando un asignador.
(plantilla de función) [editar]
Crea un puntero único que gestiona a un nuevo objeto.
(plantilla de función) [editar]
Funciones de asignación.
(función) [editar]