Con C ++ 17 , shared_ptr
se puede usar para administrar una matriz asignada dinámicamente. El shared_ptr
argumento de 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
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 podrá participar en la resolución de sobrecarga a menos que la expresión delete[] p
está bien formado y, o bien T
es U[N]
y Y(*)[N]
es convertible a T*
, o T
es
U[]
, y Y(*)[]
se puede convertir en T*
. ...
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 utilizando operator[]
element_type& operator[](ptrdiff_t i) const;
Se 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 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 estará bien formada.
Antes de C ++ 17 , shared_ptr
podría no ser utilizado para administrar matrices dinámicamente asignados. Por defecto, shared_ptr
llamará delete
al objeto administrado cuando no queden más referencias a él. Sin embargo, cuando asigna utilizando new[]
debe llamar 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;
}
};
Cree el shared_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 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 la responsabilidad del objeto administrado, a unique_ptr
es más adecuado para esta tarea, ya que tiene una especialización parcial para los tipos de matriz.
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 especificación anterior a C ++ 17 a las enumeradas anteriormente fue proporcionada por la Especificación técnica de los fundamentos de la biblioteca , que aumentó shared_ptr
para permitirle trabajar de forma inmediata para los casos en que posee una matriz de objetos. El borrador actual de los shared_ptr
cambios programados para este 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 soportar shared_ptr
matrices son:
- La definición del tipo de miembro element_type
cambia
typedef T element_type;
typedef typename remove_extent<T>::type element_type;
- Miembro operator[]
agregado
element_type& operator[](ptrdiff_t i) const noexcept;
- A diferencia de la unique_ptr
especialización parcial para matrices, tanto shared_ptr<T[]>
y shared_ptr<T[N]>
será válida y ambos se traducirá en delete[]
ser llamado en la matriz administrada 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, estará bien formada, tendrá un comportamiento bien definido y no 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*
.
std::vector
. Tendría que tener cuidado de pasar la matriz usando referencias para no hacer copias de ella. La sintaxis para acceder a los datos es más limpia que shared_ptr, y cambiar su tamaño es muy fácil. Y obtienes toda la bondad STL si alguna vez la quieres.