ptr partagé dans un tableau: devrait-il être utilisé?

Juste une petite question concernant shared_ptr.

Est-il une bonne pratique d'utiliser shared_ptr pointant vers un tableau? Par exemple,

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

Si non, alors pourquoi pas? Une raison dont je suis déjà conscient est que l'on ne peut pas incrémenter/décrémenter le shared_ptr. Par conséquent, il ne peut pas être utilisé comme un simple pointeur vers un tableau.

135
demandé sur Toby Speight 2012-10-25 09:13:00

2 réponses

Avec C++17, shared_ptr peut être utilisé pour gérer un tableau alloué dynamiquement. L'argument de modèle shared_ptr dans ce cas doit être T[N] ou T[]. Donc vous pouvez écrire

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

De n4659, [util.smartptr.partager.const]

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

Nécessite: Y doit être un type complètes. L'expression delete[] p lorsque T est de type tableau, ou delete p lorsque T n'est pas de type tableau, doit avoir bien défini le comportement, et de ne pas jeter de l' exception.
...
Remarques: Lorsque T est de type tableau, ce constructeur ne doit pas participer à la résolution de surcharge à moins que l'expression delete[] p est bien formé et soit T est U[N] et Y(*)[N] convertible T*, ou T est U[] et {[29] } est convertible en T*. ...

Pour ce faire, le type de membre element_type est maintenant défini comme

using element_type = remove_extent_t<T>;

Les éléments de tableau peuvent être accessibles en utilisant operator[]

  element_type& operator[](ptrdiff_t i) const;

Nécessite: get() != 0 && i >= 0. Si T est U[N], i < N. ...
Remarques: Lorsque T n'est pas de type tableau, il n'est pas précisé si cette fonction membre est déclaré. S'il est déclaré, Il n'est pas spécifié quel est son type de retour, sauf que la déclaration (mais pas nécessairement la définition) de la fonction doit être bien formée.


Avant C++17, shared_ptr pourrait - pas être utilisé pour gérer des tableaux alloués dynamiquement. Par défaut, shared_ptr appelle delete sur l'objet géré lorsqu'il ne lui reste plus de références. Cependant, lorsque vous allouez en utilisant new[], vous devez appeler delete[], et non delete, pour libérer la ressource.

Pour utiliser correctement shared_ptr avec un tableau, vous devez fournir un deleter personnalisé.

template< typename T >
struct array_deleter
{
  void operator ()( T const * p)
  { 
    delete[] p; 
  }
};

Créez le shared_ptr comme suit:

std::shared_ptr<int> sp(new int[10], array_deleter<int>());

Maintenant shared_ptr correctement appel de delete[] lors de la destruction de l'objet géré.

Le deleter personnalisé ci-dessus peut être remplacé par

  • Le std::default_delete spécialisation partielle pour les types de tableaux

    std::shared_ptr<int> sp(new int[10], std::default_delete<int[]>());
    
  • Une expression lambda

    std::shared_ptr<int> sp(new int[10], [](int *p) { delete[] p; });
    

En outre, sauf si vous avez réellement besoin de share onwership de l'objet géré, un unique_ptr est mieux adapté à cette tâche, car il a une spécialisation partielle pour les types de tableaux.

std::unique_ptr<int[]> up(new int[10]); // this will correctly call delete[]

Changements introduits par les Extensions C++ pour les fondamentaux de la bibliothèque

Une autre alternative pré-C++17 à la ceux énumérés ci-dessus ont été fournis par la spécification technique Library Fundamentals, qui a augmenté shared_ptr pour lui permettre de travailler hors de la boîte pour les cas où il possède un tableau d'objets. Le projet actuel des shared_ptr changements prévus pour ce TS SE TROUVE dans N4082 . Ces modifications seront accessibles via l'espace de noms std::experimental et incluses dans l'en-tête <experimental/memory>. Quelques-unes des modifications pertinentes à prendre en charge shared_ptr pour les tableaux sont:

- la définition de La type de membre element_type changements

typedef T element_type;

 typedef typename remove_extent<T>::type element_type;

- Membre operator[] est ajouté

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

- contrairement à la spécialisation partielle unique_ptr pour les tableaux, les deux shared_ptr<T[]> et shared_ptr<T[N]> seront valides et les deux entraîneront l'appel de delete[] sur le tableau d'objets géré.

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

Nécessite: Y doit être un type complètes. L'expression delete[] p lorsque T est de type tableau, ou delete p, lorsque T n'est pas un type de tableau, doit être bien formé, doit avoir un comportement bien défini et ne doit pas lancer d'exceptions. Lorsque T est U[N], Y(*)[N] sont convertibles à T*; lorsque T est U[], Y(*)[] sont convertibles à T*; sinon Y* sont convertibles à T*.

211
répondu Praetorian 2018-05-09 16:50:52

, éventuellement, Un alternative plus facile que vous pourriez être en mesure d'utiliser est shared_ptr<vector<int>>.

25
répondu Timmmm 2013-10-03 13:06:39