Juste une petite question concernant shared_ptr
.
Est-ce une bonne pratique d’utiliser _shared_ptr
_ en pointant vers un tableau? Par exemple,
_shared_ptr<int> sp(new int[10]);
_
Si non, alors pourquoi pas? Une des raisons que je connais déjà est qu’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 vers un tableau.
Avec C++ 17 , _shared_ptr
_ peut être utilisé pour gérer un tableau alloué de manière dynamique. 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]);
_
À partir de n4659, [util.smartptr.shared.const]
_template<class Y> explicit shared_ptr(Y* p);
_Nécessite:
Y
doit être un type complet. L'expression _delete[] p
_, lorsqueT
est un type de tableau, ou _delete p
_, lorsqueT
n'est pas un type de tableau, doit avoir un comportement bien défini et ne pas lever d'exceptions. .
...
Remarques: LorsqueT
est un type de tableau, ce constructeur ne doit pas participer à la résolution de surcharge sauf si l'expression _delete[] p
_ est bien formée. et soitT
est _U[N]
_ etY(*)[N]
est convertible en _T*
_ ouT
est _U[]
_ etY(*)[]
est convertible en _T*
_. ...
Pour supporter cela, 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 utilisés avec operator[]
_element_type& operator[](ptrdiff_t i) const;
_requiert:
get() != 0 && i >= 0
. SiT
est _U[N]
_, _i < N
_. ...
Remarques: LorsqueT
n'est pas un type de tableau, il n'est pas précisé si cette fonction membre est déclarée. Si elle est déclarée, le type de son retour n'est pas spécifié, sauf que la déclaration (bien que 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
_ appellera delete
sur l'objet géré lorsqu'il ne restera plus de références. Toutefois, lorsque vous allouez avec _new[]
_, vous devez appeler _delete[]
_ et non pas 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>());
_
Désormais, _shared_ptr
_ appellera correctement _delete[]
_ lors de la destruction de l'objet géré.
Le deleter personnalisé ci-dessus peut être remplacé par
la spécialisation partielle std::default_delete
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; });
_
De même, à moins que vous n'ayez réellement besoin de partager l'authenticité de partage de l'objet géré, un _unique_ptr
_ convient mieux à cette tâche, car il dispose d'une spécialisation partielle pour les types de tableau.
_std::unique_ptr<int[]> up(new int[10]); // this will correctly call delete[]
_
Une autre solution d’avant C++ 17 à celles énumérées ci-dessus a été fournie par le Spécification technique des bases de la bibliothèque , qui a augmenté _shared_ptr
_ pour lui permettre de fonctionner immédiatement avec les cas suivants: possède un tableau d'objets. 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 _<experimental/memory>
_. Voici quelques modifications pertinentes à prendre en charge pour _shared_ptr
_ pour les tableaux:
- La définition du type de membre _element_type
_ change
typedef T type_élément;_typedef typename remove_extent<T>::type element_type;
_
- Le membre _operator[]
_ est ajouté
_element_type& operator[](ptrdiff_t i) const noexcept;
_
- Contrairement à la spécialisation partielle _unique_ptr
_ pour les tableaux, _shared_ptr<T[]>
_ et _shared_ptr<T[N]>
_ sont 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);
_Requiert :
Y
doit être un type complet. L'expression _delete[] p
_, lorsqueT
est un type de tableau, ou _delete p
_, lorsqueT
n'est pas un type de tableau, doit être correctement formé et doit avoir un comportement bien défini. et ne jettera pas d'exceptions. LorsqueT
est _U[N]
_,Y(*)[N]
doit être convertible en _T*
_; lorsqueT
est _U[]
_,Y(*)[]
doit être convertible en _T*
_; sinon, _Y*
_ doit pouvoir être converti en _T*
_.
Une alternative peut-être plus facile à utiliser est shared_ptr<vector<int>>
.