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óndelete[] p
, cuandoT
es un tipo de matriz, odelete p
, cuandoT
no es un tipo de matriz, tendrá un comportamiento bien definido y no arrojará excepciones.
...
Observaciones: cuandoT
es un tipo de matriz, este constructor no participará en la resolución de sobrecarga a menos que la expresióndelete[] p
esté bien formada yT
seaU[N]
eY(*)[N]
sea convertible aT*
, oT
esU[]
eY(*)[]
es convertible aT*
. ...
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
. SiT
esU[N]
,i < N
. ...
Observaciones: CuandoT
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 matrizstd::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óndelete[] p
, cuandoT
es un tipo de matriz, odelete p
, cuandoT
no es un tipo de matriz, debe estar bien formada, debe tener un comportamiento bien definido y no debe arrojar excepciones. CuandoT
esU[N]
,Y(*)[N]
será convertible aT*
; cuandoT
esU[]
,Y(*)[]
será convertible aT*
; de lo contrario,Y*
será convertible aT*
.
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>>
.