Réponses:
C'est facile lorsque vous avez des propriétés que vous pouvez attribuer à chaque pointeur intelligent. Il existe trois propriétés importantes.
Le premier signifie qu'un pointeur intelligent ne peut pas supprimer l'objet, car il ne le possède pas. Le second signifie qu'un seul pointeur intelligent peut pointer vers le même objet en même temps. Si le pointeur intelligent doit être renvoyé des fonctions, la propriété est transférée au pointeur intelligent renvoyé, par exemple.
Le troisième signifie que plusieurs pointeurs intelligents peuvent pointer vers le même objet en même temps. Cela s'applique également à un pointeur brut , mais les pointeurs bruts manquent d'une fonctionnalité importante: ils ne définissent pas s'ils sont propriétaires ou non. Un pointeur intelligent de partage de propriété supprimera l'objet si chaque propriétaire abandonne l'objet. Ce comportement est souvent nécessaire, de sorte que les pointeurs intelligents partagés sont largement répandus.
Certains propriétaires de pointeurs intelligents ne prennent en charge ni le deuxième ni le troisième. Ils ne peuvent donc pas être renvoyés par les fonctions ou passés ailleurs. Ce qui est le plus approprié pour les RAII
cas où le pointeur intelligent est maintenu local et est juste créé pour libérer un objet après qu'il soit hors de portée.
La part de propriété peut être implémentée en ayant un constructeur de copie. Cela copie naturellement un pointeur intelligent et la copie et l'original feront référence au même objet. Le transfert de propriété ne peut pas vraiment être implémenté en C ++ actuellement, car il n'y a aucun moyen de transférer quelque chose d'un objet à un autre pris en charge par le langage: si vous essayez de renvoyer un objet à partir d'une fonction, ce qui se passe, c'est que l'objet est copié. Un pointeur intelligent qui implémente le transfert de propriété doit donc utiliser le constructeur de copie pour implémenter ce transfert de propriété. Cependant, cela à son tour rompt son utilisation dans les conteneurs, car les exigences indiquent un certain comportement du constructeur de copie des éléments des conteneurs qui est incompatible avec ce comportement dit de "constructeur en mouvement" de ces pointeurs intelligents.
C ++ 1x fournit une prise en charge native du transfert de propriété en introduisant les soi-disant «constructeurs de déplacement» et «opérateurs d'affectation de déplacement». Il est également livré avec un tel pointeur intelligent de transfert de propriété appelé unique_ptr
.
scoped_ptr
est un pointeur intelligent qui n'est ni transférable ni partageable. Il est juste utilisable si vous avez besoin d'allouer de la mémoire localement, mais assurez-vous qu'il est à nouveau libéré lorsqu'il sort de la portée. Mais il peut toujours être échangé avec un autre scoped_ptr, si vous le souhaitez.
shared_ptr
est un pointeur intelligent qui partage la propriété (troisième type ci-dessus). Il est compté par référence afin qu'il puisse voir quand la dernière copie en est hors de portée, puis il libère l'objet géré.
weak_ptr
est un pointeur intelligent non propriétaire. Il est utilisé pour référencer un objet géré (géré par un shared_ptr) sans ajouter de compte de référence. Normalement, vous devez extraire le pointeur brut du shared_ptr et le copier. Mais ce ne serait pas sûr, car vous n'auriez aucun moyen de vérifier quand l'objet a été réellement supprimé. Ainsi, faiblesse_ptr fournit des moyens en référençant un objet géré par shared_ptr. Si vous devez accéder à l'objet, vous pouvez verrouiller sa gestion (pour éviter que dans un autre thread, shared_ptr le libère pendant que vous utilisez l'objet), puis l'utiliser. Si le faiblesse_ptr pointe vers un objet déjà supprimé, il vous remarquera en lançant une exception. L'utilisation de faiblesse_ptr est plus avantageuse lorsque vous avez une référence cyclique: le comptage de références ne peut pas facilement faire face à une telle situation.
intrusive_ptr
est comme un shared_ptr mais il ne conserve pas le compte de référence dans un shared_ptr mais laisse incrémenter / décrémenter le compte à certaines fonctions d'assistance qui doivent être définies par l'objet qui est géré. Cela présente l'avantage qu'un objet déjà référencé (dont le compte de référence est incrémenté par un mécanisme de comptage de référence externe) peut être inséré dans un intrusive_ptr - car le compte de référence n'est plus interne au pointeur intelligent, mais le pointeur intelligent utilise un existant mécanisme de comptage des références.
unique_ptr
est un pointeur de transfert de propriété. Vous ne pouvez pas le copier, mais vous pouvez le déplacer en utilisant les constructeurs de déplacement de C ++ 1x:
unique_ptr<type> p(new type);
unique_ptr<type> q(p); // not legal!
unique_ptr<type> r(move(p)); // legal. p is now empty, but r owns the object
unique_ptr<type> s(function_returning_a_unique_ptr()); // legal!
C'est la sémantique que std :: auto_ptr obéit, mais en raison du manque de support natif pour le déplacement, il ne parvient pas à les fournir sans pièges. unique_ptr volera automatiquement les ressources d'un autre temporaire_unique unique qui est l'une des principales caractéristiques de la sémantique de déplacement. auto_ptr sera déconseillé dans la prochaine version de C ++ Standard au profit de unique_ptr. C ++ 1x permettra également de bourrer des objets qui ne sont que mobiles mais non copiables dans des conteneurs. Vous pouvez donc farcir unique_ptr dans un vecteur par exemple. Je m'arrête ici et je vous renvoie à un bel article à ce sujet si vous souhaitez en savoir plus.
auto_ptr
est déjà obsolète (C ++ 11).
intrusive_ptr
peut être préférable à shared_ptr
pour une meilleure cohérence du cache. Apparemment, le cache fonctionne mieux si vous stockez le nombre de références dans le cadre de la mémoire de l'objet géré lui-même au lieu d'un objet séparé. Cela peut être implémenté dans un modèle ou une superclasse de l'objet géré.
scoped_ptr est le plus simple. Quand il sort du cadre, il est détruit. Le code suivant est illégal (les scoped_ptrs ne sont pas copiables) mais illustrera un point:
std::vector< scoped_ptr<T> > tPtrVec;
{
scoped_ptr<T> tPtr(new T());
tPtrVec.push_back(tPtr);
// raw T* is freed
}
tPtrVec[0]->DoSomething(); // accessing freed memory
shared_ptr est compté par référence. Chaque fois qu'une copie ou une affectation se produit, le nombre de références est incrémenté. Chaque fois que le destructeur d'une instance est déclenché, le nombre de références pour le T * brut est décrémenté. Une fois qu'il est à 0, le pointeur est libéré.
std::vector< shared_ptr<T> > tPtrVec;
{
shared_ptr<T> tPtr(new T());
// This copy to tPtrVec.push_back and ultimately to the vector storage
// causes the reference count to go from 1->2
tPtrVec.push_back(tPtr);
// num references to T goes from 2->1 on the destruction of tPtr
}
tPtrVec[0]->DoSomething(); // raw T* still exists, so this is safe
faiblesse_ptr est une référence faible à un pointeur partagé qui vous oblige à vérifier si le pointé vers shared_ptr est toujours là
std::vector< weak_ptr<T> > tPtrVec;
{
shared_ptr<T> tPtr(new T());
tPtrVec.push_back(tPtr);
// num references to T goes from 1->0
}
shared_ptr<T> tPtrAccessed = tPtrVec[0].lock();
if (tPtrAccessed[0].get() == 0)
{
cout << "Raw T* was freed, can't access it"
}
else
{
tPtrVec[0]->DoSomething(); // raw
}
intrusive_ptr est généralement utilisé lorsqu'il existe un ptr intelligent tiers que vous devez utiliser. Il appellera une fonction gratuite pour ajouter et diminuer le nombre de références.Voir le lien pour booster la documentation pour plus d'informations.
if (tPtrAccessed[0].get() == 0)
censé être if (tPtrAccessed.get() == 0)
?
Ne négligez boost::ptr_container
aucune enquête sur les pointeurs intelligents boost. Ils peuvent être inestimables dans des situations où un exemple std::vector<boost::shared_ptr<T> >
serait trop lent.
J'appuie les conseils sur la consultation de la documentation. Ce n'est pas aussi effrayant qu'il n'y paraît. Et quelques petits conseils:
scoped_ptr
- un pointeur supprimé automatiquement lorsqu'il sort du champ d'application. Remarque - aucune affectation possible, mais n'introduit pas de surchargeintrusive_ptr
- pointeur de comptage de référence sans surcharge de smart_ptr
. Cependant, l'objet lui-même stocke le nombre de référencesweak_ptr
- collabore avec shared_ptr
pour faire face aux situations entraînant des dépendances circulaires (lire la documentation et rechercher sur google pour une belle image;)shared_ptr
- le générique, le plus puissant (et le plus lourd) des pointeurs intelligents (parmi ceux proposés par boost)auto_ptr
, qui garantit que l'objet vers lequel il pointe est automatiquement détruit lorsque le contrôle quitte une portée. Cependant, il a une sémantique de copie différente de celle du reste des gars.unique_ptr
- viendra avec C ++ 0xRéponse à modifier: Oui