ptr compartido a una matriz: ¿debería usarse?


Sólo 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, entonces ¿por qué no? Una razón de la que ya soy consciente es que uno no puede incrementar/disminuir el shared_ptr. Por lo tanto, no se puede utilizar como un puntero normal a una matriz.

Author: Toby Speight, 2012-10-25

2 answers

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

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

De n4659, [útil.smartptr.compartir.const]

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

Requiere: Y será un tipo completo. La expresión delete[] p, {cuando[18]} es un tipo de matriz, o delete p, {cuando[18]} no es un tipo de matriz, se tiene bien definido el comportamiento, y no tirar salvedad.
...
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] y Y(*)[N] sea convertible a T*, o T sea U[] y Y(*)[] es convertible a T*. ...

Para soportar esto, el tipo miembroelement_type se define ahora como

using element_type = remove_extent_t<T>;

Los elementos del array pueden ser accedidos usando 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 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 debe estar bien formada.


Antes de C++17, shared_ptr se podría usar no para administrar arrays dinámicamente asignados. De forma predeterminada, shared_ptr llamará a delete en el objeto administrado cuando no queden más referencias a él. Sin embargo, cuando se asigna usando new[] es necesario llamar a delete[], y no a delete, para liberar el recurso.

Para usar correctamente shared_ptr con una matriz, debe proporcionar un deleter 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 a delete[] al destruir el objeto administrado.

El deleter personalizado anterior puede ser reemplazado por

  • El std::default_delete especializació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 onwership del objeto administrado, un 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 Bibliotecas

Otra alternativa pre-C++17 a la los mencionados anteriormente fueron proporcionados por la Especificación Técnica Library Fundamentals , que aumentó shared_ptr para permitir que funcione fuera de la caja 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. Estos cambios serán accesibles a través del espacio de nombres std::experimental, e incluidos en el encabezado <experimental/memory>. Algunos de los cambios relevantes para soportar shared_ptr para arrays son:

- la definición de La tipo de miembro element_type cambios

typedef T element_type;

 typedef typename remove_extent<T>::type element_type;

- Se añade el miembro operator[]

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

- A diferencia de la especialización parcial de unique_ptr para los arrays, tanto shared_ptr<T[]> como shared_ptr<T[N]> serán válidos y ambos resultarán en que delete[] sea llamado en el array administrado de objetos.

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

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

 211
Author: Praetorian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-09 16:50:52

Una alternativa posiblemente más fácil que podría ser capaz de utilizar es shared_ptr<vector<int>>.

 25
Author: Timmmm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-03 13:06:39