Question

boost :: shared_ptr a un constructeur inhabituel

template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p);

et je suis un peu perplexe quant à l'utilité de cela. Il partage la propriété avec r , mais .get () renverra p . pas r.get () !

Cela signifie que vous pouvez faire quelque chose comme ceci:

int main() {
    boost::shared_ptr<int> x(new int);
    boost::shared_ptr<int> y(x, new int);

    std::cout << x.get() << std::endl;
    std::cout << y.get() << std::endl;

    std::cout << x.use_count() << std::endl;
    std::cout << y.use_count() << std::endl;
}

Et vous obtiendrez ceci:

0x8c66008
0x8c66030
2
2

Notez que les pointeurs sont séparés, mais ils prétendent tous deux avoir un nombre_utilisations de 2 (puisqu'ils partagent la propriété du même objet).

Ainsi, le int appartenant à x existera aussi longtemps que x ou y est autour. Et si je comprends bien la documentation, le second int n'est jamais détruit. J'ai confirmé cela avec le programme de test suivant:

struct T {
    T() { std::cout << "T()" << std::endl; }
    ~T() { std::cout << "~T()" << std::endl; }
};

int main() {
    boost::shared_ptr<T> x(new T);
    boost::shared_ptr<T> y(x, new T);

    std::cout << x.get() << std::endl;
    std::cout << y.get() << std::endl;

    std::cout << x.use_count() << std::endl;
    std::cout << y.use_count() << std::endl;
}

Cette sortie (comme prévu):

T()
T()
0x96c2008
0x96c2030
2
2
~T()

Alors ... quelle est l'utilité de cette construction inhabituelle qui partage la propriété d'un pointeur, mais agit comme un autre pointeur (qu'il ne possède pas) lorsqu'elle est utilisée.

Était-ce utile?

La solution

Cela est utile lorsque vous souhaitez partager un membre de la classe et qu'une instance de la classe est déjà un shared_ptr, comme suit:

struct A
{
  int *B; // managed inside A
};

shared_ptr<A>   a( new A );
shared_ptr<int> b( a, a->B );

ils partagent le nombre d'utilisations et d'autres choses. C'est l'optimisation de l'utilisation de la mémoire.

Autres conseils

Pour en savoir plus sur leiz et piotr's réponses, cette description de shared_ptr < > "aliasing" provient d'un document du WG21, " Amélioration de shared_ptr pour C ++ 0x, révision 2 ":

  

III. Prise en charge du crénelage

     

Les utilisateurs avancés ont souvent besoin de la   possibilité de créer un shared_ptr   instance p qui partage la propriété avec   un autre (maître) shared_ptr q mais   pointe sur un objet qui n'est pas une base   de * q . * p peut être un membre ou un   élément de * q , par exemple. Ce   la section propose un complément   constructeur qui peut être utilisé pour cela   but.

     

Un effet secondaire intéressant de cette   augmentation du pouvoir d'expression est que   maintenant les fonctions * _ pointer_cast peuvent   être mis en œuvre dans le code utilisateur. le   Présentation de la fonction d'usine make_shared   plus tard dans ce document peut également être   mis en œuvre en utilisant uniquement le public   interface de shared_ptr via le   constructeur de repliement.

     

Impact:

     

Cette fonctionnalité étend l'interface de    shared_ptr dans une version rétro-compatible   manière qui augmente son expressif   pouvoir et est donc fortement   recommandé d'être ajouté au C ++ 0x   la norme. Il n'introduit aucune source et   problèmes de compatibilité binaire.

     

Texte proposé:

     

Ajouter à shared_ptr   [util.smartptr.shared] ce qui suit   constructeur:

     
template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );
  
     

Ajouter ce qui suit à   [util.smartptr.shared.const]:

     
<*>          

Effets: Construit une instance shared_ptr qui stocke p et partage la propriété avec r .

         

Post-conditions: get () == p & amp; & amp; use_count () == r.use_count () .

         

Lance: rien.

         

[Remarque: Pour éviter la possibilité d’un pointeur en suspension, l’utilisateur     de ce constructeur doit s'assurer que p reste valide au moins     jusqu'à ce que le groupe de propriété de r soit détruit. - note de fin.]

         

[Remarque: Ce constructeur permet de créer un vide code_partagé .     instance avec un pointeur stocké non NULL. - note de fin.]

  

Vous pouvez également l'utiliser pour conserver des pointeurs dynamiques, c.-à-d.:

class A {};
class B: public A {};

shared_ptr<A> a(new B);
shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));

Vous pouvez avoir un pointeur sur un pilote ou la structure de données d'une API de niveau inférieur pouvant allouer des données supplémentaires par son API de niveau inférieur ou par un autre moyen. Dans ce cas, il peut être intéressant d'augmenter le nombre_utilisations, mais de renvoyer les données supplémentaires si le premier pointeur est propriétaire des autres pointeurs de données.

J'ai utilisé le constructeur d'alias de shared_ptr dans ma petite bibliothèque:

http://code.google.com/p/infectorpp/ (seulement mon conteneur IoC simple)

Le fait est que puisque j'avais besoin d'un shared_ptr de type connu pour être renvoyé d'une classe polymorphe (qui ne connaît pas le type). Je n'ai pas pu convertir implicitement le shared_ptr au type dont j'avais besoin.

Dans le fichier & InfectorHelpers.hpp " (lignes 72 à 99), vous pouvez voir cela en action pour le type IAnyShared.

Le constructeur d'alias crée un objet shared_ptr qui ne supprime pas les pointeurs vers lesquels il pointe, mais il augmente toujours le compteur de références vers l'objet d'origine, ce qui peut s'avérer extrêmement utile.

En principe, vous pouvez créer un pointeur sur n'importe quoi à l'aide du constructeur d'alias et le menacer comme compteur de référence.

//my class
std::shared_ptr<T> ist;
int a; //dummy variable. I need its adress

virtual std::shared_ptr<int> getReferenceCounter(){
    return std::shared_ptr<int>(ist,&a); //not intended for dereferencing
}

virtual void* getPtr(); //return raw pointer to T

nous avons maintenant à la fois un "compteur de référence" et et un pointeur sur une résistance de T, suffisamment de données pour créer quelque chose avec le constructeur d'aliasing

std::shared_ptr<T> aPtr( any->getReferenceCounter(), //share same ref counter 
               static_cast<T*>(any->getPtr()) ); //potentially unsafe cast!

Je ne prétends pas avoir inventé cette utilisation pour le constructeur d'aliasing, mais je n'ai jamais vu quelqu'un d'autre faire de même. Si vous devinez si ce code corrompu fonctionne, la réponse est oui.

For & shared_ptr < B > b (a, dynamic_cast < B * > (a.get ())); "

Je pense que ce n'est pas la méthode recommandée avec le pointeur intelligent.

La méthode recommandée pour effectuer cette conversion de type devrait être:

shared_ptr<B> b(a);

Depuis dans le document Boost, il est mentionné que:

  

shared_ptr < T > peut être implicitement   converti en shared_ptr < U > à chaque fois que T *   peut être implicitement converti en U *. Dans   En particulier, shared_ptr < T > est   convertible implicitement en shared_ptr < T > const ,   vers shared_ptr < U > où U est un   base accessible de T, et à    shared_ptr < void > .

De plus, nous avons également dynamic_pointer_cast . qui pourrait effectuer directement la conversion sur un objet Smart Pointer et ces deux méthodes seraient beaucoup plus sûres que la méthode du pointeur brut de conversion manuelle.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top