les pointeurs intelligents (boost) expliqués

Quelle est la différence entre l’ensemble de pointeurs suivant? Quand utilisez-vous chaque pointeur dans le code de production, le cas échéant?

Des exemples seraient appréciés!

  1. scoped_ptr

  2. shared_ptr

  3. weak_ptr

  4. intrusive_ptr

Utilisez-vous un coup de pouce dans le code de production?

Propriétés de base des pointeurs intelligents

C’est facile lorsque vous avez des propriétés que vous pouvez affecter à chaque pointeur intelligent. Il y a trois propriétés importantes.

  • pas de propriété du tout
  • transfert de propriété
  • part de propriété

Le premier signifie qu’un pointeur intelligent ne peut pas supprimer l’object, car il ne le possède pas. La seconde signifie qu’un seul pointeur intelligent peut pointer sur le même object en même temps. Si le pointeur intelligent doit être renvoyé par les fonctions, la propriété est transférée au pointeur intelligent renvoyé, par exemple.

La troisième signifie que plusieurs pointeurs intelligents peuvent pointer vers le même object en même temps. Cela s’applique également à un pointeur brut , mais les pointeurs bruts ne disposent pas d’une caractéristique importante: ils ne définissent pas s’ils possèdent ou non. Un pointeur intelligent de partage de propriété supprime l’object si chaque propriétaire abandonne l’object. Ce comportement est souvent nécessaire, de sorte que les pointeurs intelligents partageant la propriété 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 de fonctions ou passés ailleurs. Ce qui convient le mieux aux applications RAII où le pointeur intelligent est maintenu local et vient d’être créé, ce qui libère un object une fois qu’il est hors de scope.

Le partage de propriété peut être implémenté en ayant un constructeur de copie. Cela copie naturellement un pointeur intelligent et la copie et l’original référenceront le même object. 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 object à un autre supporté par le langage: Si vous essayez de renvoyer un object depuis une fonction, l’object est copié. Ainsi, un pointeur intelligent qui implémente un transfert de propriété doit utiliser le constructeur de copie pour implémenter ce transfert de propriété. Cependant, cela interrompt à son tour son utilisation dans les conteneurs, car les exigences énoncent un certain comportement du constructeur de copie d’éléments de conteneurs qui est incompatible avec ce comportement dit “constructeur mobile” de ces pointeurs intelligents.

C ++ 1x fournit un support natif pour le transfert de propriété en introduisant des “constructeurs de déplacement” et des “opérateurs d’affectation de déplacement”. Il est également livré avec un tel pointeur intelligent de transfert de propriété appelé unique_ptr .

Classement des pointeurs intelligents

scoped_ptr est un pointeur intelligent qui n’est ni transférable ni partageable. Il est juste utilisable si vous avez besoin localement d’allouer de la mémoire, mais assurez-vous qu’il est libéré quand il est hors de scope. 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é comme référence afin de voir quand la dernière copie de celui-ci est hors de scope et libère ensuite l’object géré.

weak_ptr est un pointeur intelligent non propriétaire. Il sert à référencer un object géré (géré par shared_ptr) sans append de compte de référence. Normalement, vous devez extraire le pointeur brut du shared_ptr et le copier. Mais cela ne serait pas sûr, car vous n’auriez pas le moyen de vérifier quand l’object a été réellement supprimé. Donc, faiblesse_ptr fournit des moyens en référençant un object géré par shared_ptr. Si vous avez besoin d’accéder à l’object, vous pouvez en verrouiller la gestion (pour éviter que dans un autre thread un shared_ptr le libère pendant que vous utilisez l’object), puis l’utiliser. Si le faible_ptr pointe sur un object déjà supprimé, il vous remarquera en lançant une exception. L’utilisation de faible_ptr est particulièrement utile 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’object géré. Cela a l’avantage qu’un object déjà référencé (qui a un compte de référence incrémenté par un mécanisme de comptage de référence externe) peut être placé dans un intrusive_ptr – parce que le compteur de référence n’est plus interne au pointeur intelligent, mais le pointeur intelligent mécanisme de comptage de référence.

unique_ptr est un pointeur de transfert de propriété. Vous ne pouvez pas le copier, mais vous pouvez le déplacer à l’aide des constructeurs de déplacement de C ++ 1x:

 unique_ptr p(new type); unique_ptr q(p); // not legal! unique_ptr r(move(p)); // legal. p is now empty, but r owns the object unique_ptr s(function_returning_a_unique_ptr()); // legal! 

C’est la sémantique à laquelle std :: auto_ptr obéit, mais à cause de l’absence de support natif pour le déplacement, elle ne parvient pas à leur fournir des pièges. unique_ptr volera automatiquement les ressources d’un autre unique_ptr temporaire, qui est l’une des caractéristiques clés de la sémantique de déplacement. auto_ptr sera déprécié dans la prochaine version de C ++ Standard en faveur de unique_ptr. C ++ 1x autorisera également les objects de remplissage qui ne sont que mobiles mais non copiables dans les conteneurs. Ainsi, vous pouvez, par exemple, insérer des fichiers uniques dans un vecteur. Je vais m’arrêter ici et vous référer à un bon article à ce sujet si vous voulez en savoir plus à ce sujet.

scoped_ptr est le plus simple. Quand il est hors de scope, il est détruit. Le code suivant est illégal (scoped_ptrs ne sont pas copiables) mais illustrera un point:

 std::vector< scoped_ptr > tPtrVec; { scoped_ptr tPtr(new T()); tPtrVec.push_back(tPtr); // raw T* is freed } tPtrVec[0]->DoSomething(); // accessing freed memory 

shared_ptr est la référence comptée. Chaque fois qu’une copie ou une affectation se produit, le compte de référence est incrémenté. Chaque fois qu’un destructeur d’instance est déclenché, le compte de référence pour le T * brut est décrémenté. Une fois qu’il est 0, le pointeur est libéré.

 std::vector< shared_ptr > tPtrVec; { shared_ptr 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 pour voir si le pointé shared_ptr est toujours présent

 std::vector< weak_ptr > tPtrVec; { shared_ptr tPtr(new T()); tPtrVec.push_back(tPtr); // num references to T goes from 1->0 } shared_ptr 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é lorsque vous devez utiliser un ptr intelligent tiers. Il appellera une fonction gratuite pour append et décrémenter le nombre de références. Voir le lien pour booster la documentation pour plus d’informations.

Ne boost::ptr_container pas boost::ptr_container dans aucune enquête sur les pointeurs intelligents de boost. Ils peuvent être inestimables dans les situations où un exemple std::vector > serait trop lent.

J’appuie le conseil sur la documentation. Ce n’est pas aussi effrayant qu’il y paraît. Et quelques petits indices:

  • scoped_ptr – un pointeur automatiquement supprimé lorsqu’il est hors de scope. Remarque – aucune affectation possible, mais pas de surcharge
  • intrusive_ptr – Pointeur de comptage de référence sans surcharge de smart_ptr . Cependant l’object lui-même stocke le compte de référence
  • weak_ptr – fonctionne avec shared_ptr pour gérer les situations entraînant des dépendances circulaires (lisez la documentation et recherchez sur google nice picture;)
  • shared_ptr – le générique, le plus puissant (et le plus lourd) des pointeurs intelligents (parmi ceux proposés par boost)
  • Il y a aussi l’ancien auto_ptr , qui garantit que l’object sur lequel il pointe est automatiquement détruit lorsque le contrôle laisse une étendue. Cependant, sa sémantique de copie est différente de celle des autres.
  • unique_ptr – viendra avec C ++ 0x

Réponse à l’édition: Oui