shared_ptr à un tableau: devrait-il être utilisé?

Juste une petite requête concernant shared_ptr .

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

 shared_ptr sp(new int[10]); 

Si non, alors pourquoi pas? Une des raisons pour lesquelles je suis déjà au courant 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 pointeur normal sur un tableau.

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

 shared_ptr sp(new int[10]); 

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

  template explicit shared_ptr(Y* p); 

Requiert: Y doit être un type complet. L’expression delete[] p , lorsque T est un type de tableau, ou delete p , lorsque T n’est pas un type de tableau, doit avoir un comportement bien défini et ne doit pas lancer d’exceptions.

Remarques: Lorsque T est un type tableau, ce constructeur ne participera pas à la résolution de la surcharge à moins que l’expression delete[] p soit bien formée et que T soit U[N] et que Y(*)[N] soit convertible en T* , ou T est U[] et Y(*)[] est convertible en T* . …

Pour supporter cela, le type de membre element_type est maintenant défini comme

 using element_type = remove_extent_t; 

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

  element_type& operator[](ptrdiff_t i) const; 

Requiert: get() != 0 && i >= 0 . Si T est U[N] , i < N . ...
Remarques: Lorsque T n'est pas un type de tableau, il n'est pas spécifié si cette fonction membre est déclarée. S'il est déclaré, son type de retour n'est pas spécifié, 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 ne pouvait pas être utilisé pour gérer les tableaux alloués dynamicment. Par défaut, shared_ptr appelle delete sur l'object géré lorsqu'il ne lui rest 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 paramètre personnalisé.

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

Créez le shared_ptr comme suit:

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

Maintenant, shared_ptr appelle correctement delete[] lors de la destruction de l'object géré.

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

  • la spécialisation partielle std::default_delete pour les types de tableau

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

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

De plus, à moins que vous ayez réellement besoin de partager l'object géré, un unique_ptr est mieux adapté à cette tâche, car il possède une spécialisation partielle pour les types de tableau.

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

Modifications apscopes par les extensions C ++ pour les fondamentaux de bibliothèque

Une autre alternative pré-C ++ 17 à celles répertoriées ci-dessus était fournie par la spécification technique des principes fondamentaux de la bibliothèque , qui augmentait shared_ptr pour lui permettre de travailler immédiatement pour les cas où il possède un tableau d'objects. Le brouillon actuel des modifications shared_ptr prévues pour ce TS peut être trouvé dans N4082 . Ces modifications seront accessibles via l'espace de noms std::experimental et incluses dans l'en-tête . Quelques-unes des modifications pertinentes à prendre en charge pour shared_ptr pour les tableaux sont:

- La définition du type de membre changements_élément

typedef T element_type;

  typedef typename remove_extent::type element_type; 

- L' operator[] 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 et shared_ptr seront valides et tous deux entraîneront la delete[] de delete[] sur le tableau d'objects géré.

  template explicit shared_ptr(Y* p); 

Requiert : Y doit être un type complet. L'expression delete[] p , lorsque T est un type tableau, ou delete p , lorsque T n'est pas un type tableau, doit être bien formée, avoir un comportement bien défini et ne pas émettre d'exceptions. Lorsque T est U[N] , Y(*)[N] doit être convertible en T* ; lorsque T est U[] , Y(*)[] doit être convertible en T* ; sinon, Y* doit être convertible en T* .

Une alternative peut-être plus facile à utiliser est shared_ptr> .