2010-08-06 5 views
7

J'ai une classe qui utilise un mécanisme de comptage de référence. Les objets de cette classe sont finalement détruits en appelant delete this lorsque le nombre de références tombe à zéro. Ma question est: puis-je utiliser la variable locale sur la pile après delete this? Voici un exemple plus précis:Accéder à une variable locale après "supprimer ceci"

class RefCountedClass 
{ 
public: 
    RefCountedClass(Mutex& m) : 
     mutex_(m) 
    {} 

    . 
    . 
    . 

private: 
    Mutex& mutex_; 

    void RemoveReference() 
    { 
     // As I understand, mutex_ will be destroyed after delete, 
     // but using m is all right because it is on-stack and 
     // references an external object. Am I right? 
     Mutex& m = mutex_; 
     m.Acquire(); 

     --recount_; 
     if (refcount <= 0) delete this; 

     m.Release(); 
    } 
}; 
+0

objets en référence comptent eux-mêmes est une mauvaise idée (peut-il dire si Il s'agit d'une variable de durée de vie statique (pile) ou de durée de vie dynamique (tas) .C'est ainsi que fonctionne COM et des expériences acquises par la communauté C++ sur laquelle nous avons évolué, comme le montre boost :: shared_ptr où le nombre de références est –

+0

@MartinYork Je suis d'accord avec vous: dans un cas général, je ne me conseillerais pas de mettre en place un tel système. comptage de référence. C'est un cas spécial cependant. Heureusement, dans ma situation réelle, le constructeur n'est pas public et la création est protégée par un objet usine. – FireAphis

Répondre

7

Oui, you may do this, aussi longtemps que la variable membre lui-même est vraiment seulement une référence à un objet extérieur.

(S'il vous plaît pardonnez la réponse précédente mal, je suis confus au sujet de la variable mutex_.)

+0

+1 de moi. J'ai négligé ce qui était assigné à la variable locale. J'aime mieux ta réponse, alors j'ai supprimé la mienne. – Manfred

0

En général, la seule chose que vous n'êtes pas autorisé à appeler après delete this est tout ce qui fait référence à this. Cela inclut tout membre ou fonction de classe non statique.

Dans votre cas, il est fort probable que RemoveReference ne fonctionnera pas. C'est parce que m points à mutex_ qui n'existe plus après supprimer cela. Votre meilleur pari pourrait bien rendre mutex_ statique.

Edit: Bien que mutex_ des points à une variable externe qui continue d'exister après la classe est supprimée, il n'y a aucune garantie pare-balles que le compilateur ne se référer à mutex_ après la classe est supprimée pour obtenir la valeur de la mutex externe. Il y a de fortes chances que les choses fonctionnent comme prévu, mais je ne crois pas que cela puisse être garanti.

+0

Non, 'm' ne pointe pas sur' mutex_' mais sur tout ce qui touche 'mutex_': notez que' mutex_' est lui-même une référence! –

+0

Voir ma modification - Je suppose qu'une référence est traitée comme un pointeur, mais étant une référence, le compilateur peut mettre en cache la valeur de mutex_ et faire fonctionner les choses comme prévu. – doron

+3

Si le compilateur fait ce que vous spéculez, il est cassé. C'est légal C++. Autrement dit, comment cette situation est-elle différente de 'int a = myIntegerMemberVariable_; supprime ça; Quelque chose avec (a); '?N'est-il pas clair dans ce cas que tout compilateur qui "optimise" cela à "doSomethingWith (this-> myIntegerMemberVariable _);" est cassé? –

0

Oui dans ce cas. Votre variable de pile 'm' pointe vers une ressource externe que vous obtenez dans le constructeur

1

Oui, vous pouvez, mais pourquoi ne pas utiliser le décrément atomique au lieu de décrémenter le compteur sous le mutex? Et avez-vous réellement besoin de protéger (par mutex) la destruction d'objets? En effet, après que le compteur soit 0, le seul fil courant peut accéder à l'objet.

Alors, peut-être il est possible de réécrire votre code comme

 
    int tmp_count; 
    m.Acquire(); 
     tmp_count= --recount_; 
    m.Release(); 
    if (tmp_count <= 0) delete this; 

(ou utiliser Atomics pour Décrémenter et tester le compteur)

+1

** Dangereux **! Cela peut double-supprimer puisque vous testez pour 'tmp_count <= 0'. Il serait prudent de tester '== 0' à la place. Mais cet exemple illustre magnifiquement pourquoi le code concurrent est si difficile à obtenir. –

+0

Il est dangereux si le programme contient un autre bug (recount_ ne peut pas être <0 sinon); mais généralement je suis d'accord que == est plus acceptable dans ce cas. +1 sur le code concurrent. Le temps consacré à l'analyse et à la vérification d'un tel code peut être 10, 20, 50 fois supérieur au temps consacré à l'écriture. – user396672

Questions connexes