82 votes

Exemple d'utilisation de shared_ptr?

Salut j'ai posé une question aujourd'hui de savoir Comment insérer différents types d'objets dans le même tableau de vecteurs et mon code en question

 gate* G[1000];
G[0] = new ANDgate() ;
G[1] = new ORgate;
//gate is a class inherited by ANDgate and ORgate classes
class gate
{
 .....
 ......
 virtual void Run()
   {   //A virtual function
   }
};
class ANDgate :public gate 
  {.....
   .......
   void Run()
   {
    //AND version of Run
   }  

};
 class ORgate :public gate 
  {.....
   .......
   void Run()
   {
    //OR version of Run
   }  

};      
//Running the simulator using overloading concept
 for(...;...;..)
 {
  G[i]->Run() ;  //will run perfectly the right Run for the right Gate type
 } 

et je voulais utiliser des vecteurs donc, quelqu'un a écrit que je dois faire :

std::vector<gate*> G;
G.push_back(new ANDgate); 
G.push_back(new ORgate);
for(unsigned i=0;i<G.size();++i)
{
  G[i]->Run();
}

mais alors qu'il et beaucoup d'autres ont suggéré que je serais mieux utiliser Boost pointeur de conteneurs
ou shared_ptr. J'ai passé les 3 dernières heures de lecture sur ce sujet, mais la documentation semble assez avancé pour moi . **Quelqu'un peut-il me donner un petit exemple de code d' shared_ptr d'utilisation et pourquoi ils ont suggéré l'utilisation d' shared_ptr. Aussi existe-il d'autres types, comme ptr_vector, ptr_list et ptr_deque **

Edit1: j'ai lu un exemple de code en trop, ce qui comprend:

typedef boost::shared_ptr<Foo> FooPtr;
.......
int main()
{
  std::vector<FooPtr>         foo_vector;
........
FooPtr foo_ptr( new Foo( 2 ) );
  foo_vector.push_back( foo_ptr );
...........
}

Et je ne comprends pas la syntaxe!

116voto

D.Shawley Points 30324

À l'aide d'un vector de shared_ptr supprime la possibilité d'une fuite de mémoire parce que vous avez oublié de marcher le vecteur et appelez - delete sur chaque élément. Nous allons marcher à travers une version légèrement modifiée de l'exemple de la ligne-par-ligne.

typedef boost::shared_ptr<gate> gate_ptr;

Créer un alias pour le partage de type pointeur. Cela permet d'éviter la laideur dans le langage C++ que les résultats de typage std::vector<boost::shared_ptr<gate> > et oublier l'espace entre la clôture plus-que signes.

    std::vector<gate_ptr> vec;

Crée un vecteur vide d' boost::shared_ptr<gate> objets.

    gate_ptr ptr(new ANDgate);

Allouer un nouveau ANDgate de l'instance, et le stocker dans un shared_ptr. La raison pour ce faire séparément pour éviter un problème qui peut se produire si une opération de lancers. Ce n'est pas possible dans cet exemple. Le Boost shared_ptr "Meilleures Pratiques" d'expliquer pourquoi c'est une meilleure pratique à attribuer à un objet plutôt que d'une mesure temporaire.

    vec.push_back(ptr);

Cela crée un nouveau pointeur partagé dans le vecteur et les copies ptr . Le comptage de référence dans les entrailles de la shared_ptr s'assure que l'allocation d'un objet à l'intérieur de l' ptr est transféré en toute sécurité dans le vecteur.

Ce n'est pas expliqué, c'est que le destructeur pour l' shared_ptr<gate> s'assure que la mémoire allouée est supprimé. C'est là que la fuite de mémoire est à éviter. Le destructeur pour l' std::vector<T> assure que le destructeur pour l' T est appelée pour chaque élément stocké dans le vecteur. Cependant, le destructeur pour un pointeur (par exemple, gate*) ne supprime pas la mémoire qui vous a attribué. Qu'est ce que vous essayez d'éviter à l'aide de shared_ptr ou ptr_vector.

42voto

Ken Simon Points 1034

Je vais ajouter que l'une des choses les plus importantes à propos de shared_ptr est est de ne jamais construire avec la syntaxe suivante:

shared_ptr<Type>(new Type(...));

De cette façon, la "vraie" pointeur de Type anonymous est à votre portée, et a tenu seulement par le pointeur partagé. Ainsi, il sera impossible pour vous d'utiliser accidentellement cette "réelle" pointeur. En d'autres termes, ne jamais faire cela:

Type* t_ptr = new Type(...);
shared_ptr<Type> t_sptr ptrT(t_ptr);
//t_ptr is still hanging around!  Don't use it!

Bien que cela fonctionne, vous avez maintenant un Type* pointeur (t_ptr) dans votre fonction, qui vit à l'extérieur de l'pointeur partagé. Il est dangereux d'utiliser t_ptr n'importe où, parce que vous ne savez jamais quand le pointeur partagé qui détient elle peut détruire, et vous serez d'erreur de segmentation.

En va de même pour les pointeurs retourné par les autres classes. Si une classe n'a pas écrit mains, vous avez un pointeur, il n'est généralement pas sûr de juste les mettre dans une shared_ptr. Non, sauf si vous êtes sûr que la classe n'est plus à l'aide de cet objet. Parce que si vous ne le mettez dans un shared_ptr, et il est hors de portée, l'objet va être libéré lorsque la classe peut encore avoir besoin d'elle.

20voto

FuleSnabel Points 2769

Apprentissage de l'utilisation des pointeurs intelligents est à mon avis l'une des étapes les plus importantes pour devenir compétent programmeur C++. Comme vous le savez, à chaque fois que vous nouveau un objet à un certain point que vous voulez supprimer.

Une question que se posent est que, avec quelques exceptions, il peut être très difficile de s'assurer qu'un objet est toujours publié juste une fois dans tous les chemins d'exécution possibles.

C'est la raison pour RAII: http://en.wikipedia.org/wiki/RAII

Faire une classe d'assistance avec le but de s'assurer qu'un objet toujours supprimés une fois dans tous les chemins d'exécution.

Exemple d'une classe de ce genre est: std::auto_ptr

Mais parfois, vous voulez partager des objets avec d'autres. Il ne doit être supprimé lorsqu'il n'utilise plus.

Afin d'aider à la référence à des stratégies de comptage ont été développées, mais vous avez encore besoin de rappeler addref et release ref manuellement. Pour l'essentiel, c'est le même problème que new/delete.

C'est pourquoi boost a développé boost::shared_ptr, c'est le comptage de référence de pointeur intelligent de sorte que vous pouvez partager des objets et pas de fuite de mémoire involontairement.

Avec l'ajout de C++ tr1 il est maintenant ajouté à la norme c++, mais son nom de std::tr1::shared_ptr<>.

Je recommande l'utilisation de la norme pointeur partagé si possible. ptr_list, ptr_dequeue et sont donc autant que je me souvienne les contenants spécialisés pour les types pointeur. Je les ignore pour l'instant.

Donc, on peut commencer à partir de votre exemple:

std::vector<gate*> G; 
G.push_back(new ANDgate);  
G.push_back(new ORgate); 
for(unsigned i=0;i<G.size();++i) 
{ 
  G[i]->Run(); 
} 

Ici, le problème est maintenant que chaque fois que G passe hors champ d'application, nous fuites, les 2 objets ajoutés à G. nous allons réécrire à utiliser std::tr1::shared_ptr

// Remember to include <memory> for shared_ptr
// First do an alias for std::tr1::shared_ptr<gate> so we don't have to 
// type that in every place. Call it gate_ptr. This is what typedef does.
typedef std::tr1::shared_ptr<gate> gate_ptr;    
// gate_ptr is now our "smart" pointer. So let's make a vector out of it.
std::vector<gate_ptr> G; 
// these smart_ptrs can't be implicitly created from gate* we have to be explicit about it
// gate_ptr (new ANDgate), it's a good thing:
G.push_back(gate_ptr (new ANDgate));  
G.push_back(gate_ptr (new ORgate)); 
for(unsigned i=0;i<G.size();++i) 
{ 
   G[i]->Run(); 
} 

Lorsque G est hors de portée de la mémoire est automatiquement récupéré.

Comme un exercice que j'en proie à de nouveaux arrivants dans mon équipe avec leur demande d'écrire leur propre pointeur intelligent de la classe. Puis, après que vous vous êtes fait jeter la classe immedietly et de ne jamais l'utiliser à nouveau. Espérons que vous avez acquis des connaissances essentielles sur la façon dont un pointeur intelligent fonctionne sous le capot. Il n'y a pas de magie.

2voto

celavek Points 2107

Le coup de pouce de la documentation fournit un début très bon exemple: shared_ptr exemple (c'est en fait un vecteur de pointeurs intelligents) ou shared_ptr doc La réponse suivante par Johannes Schaub explique les pointeurs intelligents de boost assez bien: pointeurs intelligents expliqué

L'idée derrière(en aussi peu de mots que possible) ptr_vector est qu'il gère la désallocation de la mémoire derrière la stockées pointeurs pour vous: disons que vous avez un vecteur de pointeurs, comme dans votre exemple. Au moment de quitter l'application ou de quitter le champ d'application dans lequel le vecteur est défini, vous aurez à nettoyer après vous(vous avez alloué dynamiquement ANDgate et ORgate) mais juste compensation le vecteur de ne pas le faire parce que le vecteur est de stocker les pointeurs et non pas des objets réels(il ne les détruisent pas, mais ce qu'elle contient).

 // if you just do
 G.clear() // will clear the vector but you'll be left with 2 memory leaks
 ...
// to properly clean the vector and the objects behind it
for (std::vector<gate*>::iterator it = G.begin(); it != G.end(); it++)
{
  delete (*it);
}

boost::ptr_vector<> poignée de la ci-dessus pour vous - sens qu'il va libérer la mémoire derrière les pointeurs qu'il stocke.

2voto

user1808932 Points 179

Grâce à Boost, vous pouvez le faire>

 std::vector<boost::any> vecobj;
    boost::shared_ptr<string> sharedString1(new string("abcdxyz!"));    
    boost::shared_ptr<int> sharedint1(new int(10));
    vecobj.push_back(sharedString1);
    vecobj.push_back(sharedint1);
 

> pour insérer un type d'objet différent dans votre conteneur de vecteur. alors que pour y accéder, vous devez utiliser any_cast, qui fonctionne comme dynamic_cast, espère que cela fonctionnera pour vos besoins.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X