c++ - make_shared - shared_ptr:: unique




Exemple d'utilisation de shared_ptr? (5)

Salut, j'ai posé une question aujourd'hui sur la façon d'insérer différents types d'objets dans le même tableau vectoriel et mon code dans cette question était

 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 alors quelqu'un a écrit que je devrais faire cela:

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 lui et beaucoup d'autres ont suggéré que je ferais mieux d'utiliser des conteneurs pointeur Boost
ou shared_ptr . J'ai passé les 3 dernières heures à lire sur ce sujet, mais la documentation me semble assez avancée. **** Quelqu'un peut-il me donner un petit exemple de code d'utilisation shared_ptr et pourquoi ils ont suggéré d'utiliser shared_ptr . Aussi y ptr_vector il d'autres types comme ptr_vector , ptr_list et ptr_deque ** **

Edit1: J'ai lu un exemple de code qui incluait:

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!


Apprendre à utiliser des pointeurs intelligents est à mon avis l'une des étapes les plus importantes pour devenir un programmeur C ++ compétent. Comme vous le savez à chaque fois que vous créez un objet, vous voulez le supprimer.

Un problème qui se pose est qu'avec des exceptions, il peut être très difficile de s'assurer qu'un objet est toujours libéré une seule fois dans tous les chemins d'exécution possibles.

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

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

Exemple d'une classe comme ceci est: std :: auto_ptr

Mais parfois, vous aimez partager des objets avec d'autres. Il ne devrait être supprimé que lorsque plus personne ne l'utilise.

Afin d'aider avec cette référence, des stratégies de comptage ont été développées, mais vous devez toujours vous souvenir d'addref et de release ref manuellement. En substance, c'est le même problème que le nouveau / supprimer.

C'est pourquoi boost a développé boost :: shared_ptr, c'est la référence du pointeur intelligent pour que vous puissiez partager des objets et ne pas fuir la mémoire involontairement.

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

Je recommande d'utiliser le pointeur partagé standard si possible. ptr_list, ptr_dequeue et ainsi sont des conteneurs spécialisés IIRC pour les types de pointeurs. Je les ignore pour le moment.

Nous pouvons donc 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(); 
} 

Le problème ici est maintenant que chaque fois que G sort de la portée, nous perdons les 2 objets ajoutés à G. Réécrivons-le pour 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, la mémoire est automatiquement récupérée.

Dans le cadre d'un exercice dont j'ai été victime, les nouveaux arrivants de mon équipe leur demandent d'écrire leur propre classe de pointeurs intelligents. Puis, une fois que vous avez terminé, jetez la classe immédiatement et ne l'utilisez plus jamais. J'espère que vous avez acquis des connaissances cruciales sur la façon dont un pointeur intelligent fonctionne sous le capot. Il n'y a pas de magie vraiment.


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 vectoriel. tandis que pour accéder à vous devez utiliser any_cast, qui fonctionne comme dynamic_cast, espère que cela fonctionnera pour votre besoin.


L'utilisation d'un vector de shared_ptr supprime la possibilité de fuite de mémoire car vous avez oublié de parcourir le vecteur et d'appeler delete sur chaque élément. Passons en revue une version légèrement modifiée de l'exemple, ligne par ligne.

typedef boost::shared_ptr<gate> gate_ptr;

Créez un alias pour le type de pointeur partagé. Cela évite la laideur du langage C ++ qui résulte de la saisie de std::vector<boost::shared_ptr<gate> > et de l'oubli de l'espace entre les plus grands signes de fermeture.

    std::vector<gate_ptr> vec;

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

    gate_ptr ptr(new ANDgate);

Allouer une nouvelle instance ANDgate et la stocker dans un shared_ptr . La raison de faire cela séparément est d'éviter un problème qui peut se produire si une opération se déclenche. Ce n'est pas possible dans cet exemple. Les «Meilleures pratiques» de Boost shared_ptr expliquent pourquoi il est préférable d'attribuer un objet autonome à un objet temporaire plutôt qu'à un objet temporaire.

    vec.push_back(ptr);

Cela crée un nouveau pointeur partagé dans le vecteur et y copie ptr . Le comptage de référence dans les tripes de shared_ptr garantit que l'objet alloué à l'intérieur de ptr est transféré en toute sécurité dans le vecteur.

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


La documentation boost fournit un bon exemple de démarrage: shared_ptr example (il s'agit en fait d'un vecteur de pointeurs intelligents) ou shared_ptr doc La réponse suivante de Johannes Schaub explique assez bien les pointeurs intelligents : les pointeurs intelligents expliqués

L'idée derrière (en aussi peu de mots que possible) ptr_vector est qu'il gère pour vous le désallocation de la mémoire derrière les pointeurs stockés: disons que vous avez un vecteur de pointeurs comme dans votre exemple. Lorsque vous quittez l'application ou que vous quittez la portée dans laquelle le vecteur est défini, vous devrez nettoyer après vous (vous avez alloué dynamiquement ANDgate et ORgate) mais le fait de supprimer le vecteur ne le fera pas car le vecteur stocke les pointeurs et non les objets réels (il ne détruira pas mais ce qu'il 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 <> gérera le dessus pour vous - ce qui signifie qu'il libérera la mémoire derrière les pointeurs qu'il stocke.


#include <memory>
#include <iostream>

class SharedMemory {
    public: 
        SharedMemory(int* x):_capture(x){}
        int* get() { return (_capture.get()); }
    protected:
        std::shared_ptr<int> _capture;
};

int main(int , char**){
    SharedMemory *_obj1= new SharedMemory(new int(10));
    SharedMemory *_obj2 = new SharedMemory(*_obj1);
    std::cout << " _obj1: " << *_obj1->get() << " _obj2: " << *_obj2->get()
    << std::endl;
    delete _obj2;

    std::cout << " _obj1: " << *_obj1->get() << std::endl;
    delete _obj1;
    std::cout << " done " << std::endl;
}

Ceci est un exemple de shared_ptr en action. _obj2 a été supprimé mais le pointeur est toujours valide. la sortie est, ./test _obj1: 10 _obj2: 10 _obj2: 10 done





smart-pointers