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.
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'expressiondelete[] p
lorsqueT
est de type tableau, oudelete p
lorsqueT
n'est pas de type tableau, doit avoir bien défini le comportement, et de ne pas jeter de l' exception.
...
Remarques: LorsqueT
est de type tableau, ce constructeur ne doit pas participer à la résolution de surcharge à moins que l'expressiondelete[] p
est bien formé et soitT
estU[N]
etY(*)[N]
convertibleT*
, ouT
estU[]
et {[29] } est convertible enT*
. ...
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
. SiT
estU[N]
,i < N
. ...
Remarques: LorsqueT
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 tableauxstd::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'expressiondelete[] p
lorsqueT
est de type tableau, oudelete p
, lorsqueT
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. LorsqueT
estU[N]
,Y(*)[N]
sont convertibles àT*
; lorsqueT
estU[]
,Y(*)[]
sont convertibles àT*
; sinonY*
sont convertibles àT*
.
, éventuellement, Un alternative plus facile que vous pourriez être en mesure d'utiliser est shared_ptr<vector<int>>
.