¿Puedes hacer que std::shared_ptr administre una matriz asignada con una nueva T[]?
¿ Puedes señalar std::shared_ptr
una matriz? Por ejemplo,
std::shared_ptr<int> sp(new int[10]);
Si no, ¿por qué no? Una razón que ya conozco es que no se puede incrementar/disminuir el archivo std::shared_ptr
. Por lo tanto, no se puede utilizar como un puntero normal a una matriz.
Con C++17 , shared_ptr
se puede utilizar para administrar una matriz asignada dinámicamente. El shared_ptr
argumento de la plantilla 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
será un tipo completo. La expresióndelete[] p
, cuandoT
sea un tipo de matriz, odelete p
, cuandoT
no sea un tipo de matriz, deberá tener 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]
yY(*)[N]
sea convertible aT*
, oT
seaU[]
yY(*)[]
sea convertible aT*
. ...
Para admitir esto, el tipo de miembro element_type
ahora se define como
using element_type = remove_extent_t<T>;
Se puede acceder a los elementos de la matriz usandooperator[]
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 se declara esta función miembro. Si se declara, no se especifica cuál es su tipo de retorno, excepto que la declaración (aunque no necesariamente la definición) de la función deberá estar bien formada.
Antes de C++17 , noshared_ptr
se podía utilizar para administrar matrices asignadas dinámicamente. De forma predeterminada, llamará al objeto administrado cuando no queden más referencias a él. Sin embargo, cuando asigna el uso, debe llamar a , y no a , para liberar el recurso.shared_ptr
delete
new[]
delete[]
delete
Para poder utilizarlo correctamente shared_ptr
con una matriz, debe proporcionar un eliminador personalizado.
template< typename T >
struct array_deleter
{
void operator ()( T const * p)
{
delete[] p;
}
};
Cree el share_ptr de la siguiente manera:
std::shared_ptr<int> sp(new int[10], array_deleter<int>());
Ahora shared_ptr
llamará correctamente delete[]
al destruir el objeto administrado.
El eliminador personalizado anterior puede ser reemplazado por
la
std::default_delete
especialización parcial para tipos de matricesstd::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 la propiedad del objeto administrado, a unique_ptr
es más adecuado para esta tarea, ya que tiene una especialización parcial para tipos de matrices.
std::unique_ptr<int[]> up(new int[10]); // this will correctly call delete[]
Cambios introducidos por las extensiones de C++ para conceptos básicos de biblioteca
Otra alternativa anterior a C++ 17 a las enumeradas anteriormente fue proporcionada por la Especificación técnica de fundamentos de biblioteca , que se amplió shared_ptr
para permitir que funcione de inmediato en los casos en que posee una serie de objetos. El borrador actual de los shared_ptr
cambios previstos para esta TS se puede encontrar en N4082 . Se podrá acceder a estos cambios a través del std::experimental
espacio de nombres y se incluirán en el <experimental/memory>
encabezado. Algunos de los cambios relevantes para la compatibilidad shared_ptr
con matrices son:
— La definición del tipo de miembro element_type
cambia.
typedef T tipo_elemento;typedef typename remove_extent<T>::type element_type;
— Se operator[]
está agregando miembro
element_type& operator[](ptrdiff_t i) const noexcept;
— A diferencia de la unique_ptr
especialización parcial para matrices, ambos shared_ptr<T[]>
y shared_ptr<T[N]>
serán válidos y ambos resultarán en delete[]
ser llamados en la matriz de objetos administrada.
template<class Y> explicit shared_ptr(Y* p);
Requiere :
Y
será un tipo completo. La expresióndelete[] p
, cuandoT
sea un tipo de matriz, odelete p
, cuandoT
no sea un tipo de matriz, deberá estar bien formada, tendrá un comportamiento bien definido y no arrojará excepciones. CuandoT
seaU[N]
,Y(*)[N]
será convertible aT*
; cuandoT
seaU[]
,Y(*)[]
será convertible aT*
; en caso contrario,Y*
será convertible aT*
.
Una alternativa posiblemente más sencilla que podría utilizar es shared_ptr<vector<int>>
.