¿Puedes hacer que std::shared_ptr administre una matriz asignada con una nueva T[]?

Resuelto tshah06 asked hace 11 años • 2 respuestas

¿ Puedes señalar std::shared_ptruna 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.

tshah06 avatar Oct 25 '12 12:10 tshah06
Aceptado

Con C++17 , shared_ptrse puede utilizar para administrar una matriz asignada dinámicamente. El shared_ptrargumento 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ón delete[] p, cuando Tsea un tipo de matriz, o delete p, cuando Tno sea un tipo de matriz, deberá tener un comportamiento bien definido y no arrojará excepciones.
...
Observaciones: Cuando Tes un tipo de matriz, este constructor no participará en la resolución de sobrecarga a menos que la expresión delete[] pesté bien formada y Tsea U[N]y Y(*)[N]sea convertible a T*, o Tsea U[]y Y(*)[]sea convertible a T*. ...

Para admitir esto, el tipo de miembro element_typeahora 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 . Si Tes U[N], i < N. ...
Observaciones: Cuando Tno 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_ptrdeletenew[]delete[]delete

Para poder utilizarlo correctamente shared_ptrcon 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_ptrllamará correctamente delete[]al destruir el objeto administrado.

El eliminador personalizado anterior puede ser reemplazado por

  • la std::default_deleteespecialización parcial para tipos de matrices

    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 propiedad del objeto administrado, a unique_ptres 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_ptrpara permitir que funcione de inmediato en los casos en que posee una serie de objetos. El borrador actual de los shared_ptrcambios previstos para esta TS se puede encontrar en N4082 . Se podrá acceder a estos cambios a través del std::experimentalespacio de nombres y se incluirán en el <experimental/memory>encabezado. Algunos de los cambios relevantes para la compatibilidad shared_ptrcon matrices son:

— La definición del tipo de miembro element_typecambia.

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_ptrespecializació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 : Yserá un tipo completo. La expresión delete[] p, cuando Tsea un tipo de matriz, o delete p, cuando Tno sea un tipo de matriz, deberá estar bien formada, tendrá un comportamiento bien definido y no arrojará excepciones. Cuando Tsea U[N], Y(*)[N]será convertible a T*; cuando Tsea U[], Y(*)[]será convertible a T*; en caso contrario, Y*será convertible a T*.

Praetorian avatar Oct 25 '2012 05:10 Praetorian

Una alternativa posiblemente más sencilla que podría utilizar es shared_ptr<vector<int>>.

Timmmm avatar Oct 03 '2013 13:10 Timmmm