weak_ptr smart shared_ptr pointer example create c++ c++11 shared-ptr

c++ - smart - shared_ptr a una matriz: ¿debería usarse?



smart pointers c++ (2)

Con C ++ 17 , shared_ptr se puede usar para administrar una matriz dinámicamente asignada. El argumento de la plantilla shared_ptr en este caso debe ser T[N] o T[] . Entonces puedes escribir

shared_ptr<int[]> sp(new int[10]);

Desde n4659, [util.smartptr.shared.const]

template<class Y> explicit shared_ptr(Y* p);

Requiere: Y debe ser un tipo completo. La expresión delete[] p , cuando T es un tipo de matriz, o delete p , cuando T no es un tipo de matriz, tendrá un comportamiento bien definido y no arrojará excepciones.
...
Observaciones: cuando T es un tipo de matriz, este constructor no participará en la resolución de sobrecarga a menos que la expresión delete[] p esté bien formada y T sea U[N] e Y(*)[N] sea ​​convertible a T* , o T es U[] e Y(*)[] es convertible a T* . ...

Para admitir esto, el tipo de miembro element_type ahora se define como

using element_type = remove_extent_t<T>;

Los elementos de matriz se pueden acceder utilizando el operator[]

element_type& operator[](ptrdiff_t i) const;

Requiere: get() != 0 && i >= 0 . Si T es U[N] , i < N . ...
Observaciones: Cuando T no es un tipo de matriz, no se especifica si esta función miembro se declara. Si se declara, no se especifica cuál es su tipo de devolución, excepto que la declaración (aunque no necesariamente la definición) de la función debe estar bien formada.

Antes de C ++ 17 , shared_ptr no se podía usar para administrar matrices asignadas dinámicamente. De forma predeterminada, shared_ptr llamará a delete en el objeto administrado cuando no le quedan más referencias. Sin embargo, cuando asigna utilizando new[] necesita llamar a delete[] , y no delete , para liberar el recurso.

Para usar correctamente shared_ptr con una matriz, debe proporcionar un eliminador personalizado.

template< typename T > struct array_deleter { void operator ()( T const * p) { delete[] p; } };

Crea el shared_ptr de la siguiente manera:

std::shared_ptr<int> sp(new int[10], array_deleter<int>());

Ahora shared_ptr llamará correctamente a delete[] cuando destruya el objeto administrado.

El eliminador de detalles anterior puede ser reemplazado por

  • std::default_delete especialización parcial para tipos de matriz

    std::shared_ptr<int> sp(new int[10], std::default_delete<int[]>());

  • una expresión lambda

    std::shared_ptr<int> sp(new int[10], [](int *p) { delete[] p; });

Además, a menos que realmente necesite compartir el origen del objeto administrado, un unique_ptr es más adecuado para esta tarea, ya que tiene una especialización parcial para los tipos de arreglos.

std::unique_ptr<int[]> up(new int[10]); // this will correctly call delete[]

Cambios introducidos por las extensiones de C ++ para los fundamentos de la biblioteca

Otra alternativa anterior a C ++ 17 a los enumerados anteriormente fue proporcionada por la Especificación técnica de fundamentos de la biblioteca , que aumentó shared_ptr para permitir que funcione de la caja para los casos en que posee una matriz de objetos. El borrador actual de los cambios shared_ptr programados para este TS se puede encontrar en N4082 . Se podrá acceder a estos cambios a través del std::experimental nombres std::experimental , e incluirlos en el encabezado <experimental/memory> . Algunos de los cambios relevantes para soportar shared_ptr para matrices son:

- La definición del tipo de miembro element_type cambia

typedef T element_type;

typedef typename remove_extent<T>::type element_type;

- Se agrega el operator[] miembro operator[]

element_type& operator[](ptrdiff_t i) const noexcept;

- A diferencia de la especialización parcial unique_ptr para arrays, tanto shared_ptr<T[]> y shared_ptr<T[N]> serán válidos y ambos darán como resultado la shared_ptr<T[N]> delete[] en la matriz gestionada de objetos.

template<class Y> explicit shared_ptr(Y* p);

Requiere : Y debe ser un tipo completo. La expresión delete[] p , cuando T es un tipo de matriz, o delete p , cuando T no es un tipo de matriz, debe estar bien formada, debe tener un comportamiento bien definido y no debe arrojar excepciones. Cuando T es U[N] , Y(*)[N] será convertible a T* ; cuando T es U[] , Y(*)[] será convertible a T* ; de lo contrario, Y* será convertible a T* .

Solo una pequeña consulta sobre shared_ptr .

¿Es una buena práctica usar shared_ptr apuntando a una matriz? Por ejemplo,

shared_ptr<int> sp(new int[10]);

Si no, ¿por qué no? Una razón por la que ya estoy enterado es que no se puede incrementar / disminuir el shared_ptr . Por lo tanto, no se puede usar como un puntero normal a una matriz.


Una alternativa posiblemente más fácil que podría usar es shared_ptr<vector<int>> .