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’expressiondelete[] p
, lorsqueT
est un type de tableau, oudelete p
, lorsqueT
n’est pas un type de tableau, doit avoir un comportement bien défini et ne doit pas lancer d’exceptions.
…
Remarques: LorsqueT
est un type tableau, ce constructeur ne participera pas à la résolution de la surcharge à moins que l’expressiondelete[] p
soit bien formée et queT
soitU[N]
et queY(*)[N]
soit convertible enT*
, ouT
estU[]
etY(*)[]
est convertible enT*
. …
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
. SiT
estU[N]
,i < N
. ...
Remarques: LorsqueT
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[]
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'expressiondelete[] p
, lorsqueT
est un type tableau, oudelete p
, lorsqueT
n'est pas un type tableau, doit être bien formée, avoir un comportement bien défini et ne pas émettre d'exceptions. LorsqueT
estU[N]
,Y(*)[N]
doit être convertible enT*
; lorsqueT
estU[]
,Y(*)[]
doit être convertible enT*
; sinon,Y*
doit être convertible enT*
.
Une alternative peut-être plus facile à utiliser est shared_ptr
.