7
votes

Éviter les références cycliques indirectes lors de l'utilisation de Shared_PTR et Faid_ptr

Je pose actuellement une application qui repose fortement sur partagé_ptr et tout a l'air bien jusqu'à présent - j'ai fait mon devoirs et ont une très bonne idée de certains des pièges d'utilisation de partagé_ptr s.

L'un des problèmes les plus reconnus avec Shared_ptr < / Code> est des dépendances cycliques - ces problèmes peuvent être résolus en stockant faibles_ptr S qui n'affecte pas la durée de vie des objets de la chaîne. Cependant, je me débats pour obtenir la tête des heures où il est nécessaire de stocker un pointeur vers un objet externe via un faibly_ptr - Je ne suis pas sûr que ce soit interdit, découragé, ou si C'est sûr .

Le diagramme suivant décrit ce que je veux dire (les flèches noires indiquent partagée_ptr ; pointillé indiquent faibly_ptr ):

ALT Texte http://img694.imageshack.us/img694/6628/Sharedweakptr .png

  • Un parent contient Shared_ptr S à deux enfants, tous deux revenus au parent à l'aide d'un faibly_ptr .
  • dans le constructeur du premier enfant je récupère via le parent faible_ptr le pointeur sur le deuxième enfant et stockez-le localement.

    Le code ressemble à ceci: xxx

    J'ai testé cela et il semble pour travailler ok (je n'ai pas T Obtenez des rapports de fuites de mémoire), mais ma question est la suivante: est-ce sûr? Et sinon, pourquoi pas?


3 commentaires

Dupliquer possible: Stackoverflow.com/ Questions / 1826902 / ...


Pas un duplicata. J'utilise une faiblesse_ptr pour casser la référence cyclique entre le parent et l'enfant. Ma question concerne stocker un Shared_Ptr à un frère de frère, récupéré via le parent.


S'appuyant lourdement sur Shared_Ptr n'est pas une bonne idée IMHO. Ceci est un outil spécialisé avec certains cas d'utilisation à l'esprit. Dans votre exemple, pourquoi ne pas faire les enfants Scoped_ptrs et la poignée à parts d'un pointeur brut?


3 Réponses :


0
votes

Vous obtiendrez une exception Bad_weak_Ptr si 'P' était déjà détruite (d'une manière ou d'une autre). Il est donc sûr que l'enfant CTOR s'attend à des exceptions et non à la sécurité sinon.


4 commentaires

P ne peut pas être détruit valablement dans ce code, car le parent doit toujours exister: nous sommes dans une fonction membre appelée dessus. Je dirais que le constructeur enfant devrait prendre un Shared_ptr, à utiliser cela pour récupérer le pointeur Child2, mais puis stocker un pointeur faible sur le parent. Ou prendre deux paramètres. Si vous savez qu'un appelant a un partage_ptr, et la Callee doit utiliser la valeur, il n'y a pas beaucoup de point qui le passe comme un faible_ptr. S'il y a du code ailleurs qui crée des objets enfants, et n'a qu'une faibles_ptr, alors peut-être qu'un constructeur prenant faibles_ptr est juste.


Belle suggestion sur le constructeur prenant un Shared_ptr puis convertissant en une faiblesse_ptr pour le stockage - je vais donner cette pensée (verserait certainement le code quelque peu)


BTW, par "Prendre deux paramètres", je voulais dire un au parent et un à l'enfant2. Relecture, j'ai remarqué que cela pouvait être lu comme un partage_ptr et une faibles_ptr au parent, mais ce n'est pas ce que je voulais dire.


@Stevejessop " puisque le parent doit toujours exister ", vous n'avez pas besoin d'un pointeur intelligent en premier lieu. L'utilisation d'un pointeur régulier est la solution évidente, naturelle, facile et efficace.



6
votes

Le constructeur enfant semble être en sécurité comme vous l'appelez. Cependant, il n'est pas sûr en général.

La question est due à la transmission d'une faiblesse_ptr comme argument dans le constructeur enfant. Cela signifie que vous devez vous inquiéter de savoir si le pointeur faible est destiné à un objet qui n'existe plus. En modifiant ce paramètre sur un Shared_Ptrs et en convertissant en un faible lorsque nous savons que l'objet existe toujours. Voici le changement: P>

child(boost::shared_ptr<parent> p)
{
    _parent = p;
    _child2 = p->_child2; // This is this safe
}


0 commentaires

3
votes

L'un des problèmes les plus reconnus avec Shared_Ptr est des dépendances cycliques - ces problèmes peuvent être résolus en stockant des faibles_ptrs qui n'affectent pas la durée de vie des objets de la chaîne.

faux. Cette dépendance cyclique existe ou non.

Si le problème existe, alors une référence faible n'est tout simplement pas une option.

où il est nécessaire de stocker un pointeur sur un objet externe via une faiblesse_ptr

faible_ptr est presque jamais nécessaire.

Il y a peu de cas assez spécifiques où faible_ptr est approprié, mais il fait principalement partie du partagé_ptr culte: au lieu de lancer au hasard partagée_ptr Problèmes, ils jetent au hasard moitié partagés_ptr et demi faibles_ptr (comme on le voit SO).


5 commentaires

Si vous avez une dépendance cyclique, la modification d'un lien vers un pointeur faible change la nature de la dépendance, éventuellement supprimer le problème. Donc, c'est certainement une option, même s'il y en a d'autres.


@Denniszickefoose Si vous avez une dépendance cyclique, vous ne pouvez pas utiliser de faibles références. Si vous pouvez utiliser des références faibles, cela prouve que vous n'avez vraiment pas de dépendance cyclique : puisque vous pouvez faire face au fait qu'un lien peut être cassé, ce n'est pas une dépendance. Vous ne dépendez pas de quelque chose si vous n'en avez pas besoin. " Changer un lien vers un pointeur faible change la nature de la dépendance " Oui, cela change la nature de la dépendance à: pas une dépendance. Ça aide.


J'ai vu vos déclarants sur quelques questions concernant des indicateurs partagés et je suis quelque peu dans l'accord. Faible_ptr aide quelques cas, mais ne résout pas le problème général. Êtes-vous toujours de cet esprit?


@Mattjoiner Oui. "Fixation" Dépendabilité cyclique en remplaçant une référence normale (une référence forte aka) avec une "référence faible" (AKA non-A référence-à-la-tout ) est comme "Fixation" Récursion infinie en sortant après 42 niveaux de récursion. À la fin, tout ce que vous obtenez est un message d'erreur. Dans les deux cas, des programmeurs incompétents se sont concentrés sur le symptôme au lieu du problème. Il y a une histoire similaire avec une programmation sans verrouillage ou utilisant des mutiles récursives, afin d'éviter les blocages. (Dans tous les cas, je ne suis pas "opposé" à faibles références ou aux idiomes sans verrouillage. Mais ils ne sont pas des dispositifs magiques.)


Parfois, la dépendance est dans la règle des entreprises et un message d'erreur explicite pour l'utilisateur est ce qui est requis.