2010-08-06 10 views
7

Ho una classe che utilizza un meccanismo di conteggio dei riferimenti. Gli oggetti di questa classe vengono infine distrutti chiamando lo delete this quando il conteggio dei riferimenti scende a zero. La mia domanda è: posso usare la variabile on-stack locale dopo lo delete this? Ecco un esempio più specifico:Accesso a una variabile locale dopo "Elimina questo"

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

oggetti riconducibili contarsi è una cattiva idea (Può dire se è una durata di vita statica (stack) o variabile dinamica (heap) variabile. Ecco come funziona la COM e dalle esperienze maturate dalla comunità C++ che abbiamo spostato, come si può vedere da boost :: shared_ptr dove il numero di riferimenti è non fa parte dell'oggetto oggetto di referenza contato –

+0

@MartinYork Sono d'accordo con te In un caso generale non mi consiglierei di implementare tali conteggio dei riferimenti. Questo è un caso speciale però. Fortunatamente, nella mia situazione reale, il costruttore non è pubblico e la creazione è protetta da un oggetto fabbrica. – FireAphis

risposta

7

, you may do this, finché membro variabile stessa è in realtà solo un riferimento ad un oggetto esterno.

(Si prega di perdonare la risposta sbagliata precedente, ero confuso circa la variabile mutex_.)

+0

+1 da me. Ho trascurato ciò che è stato assegnato alla variabile locale. Mi piace la tua risposta meglio, quindi ho cancellato la mia. – Manfred

0

Generalmente l'unica cosa che non ti è permesso di chiamare dopo delete this è tutto ciò che rende un riferimento a this. Questo include qualsiasi membro o funzione della classe non statica.

Nel tuo caso, c'è una buona possibilità che RemoveReference non funzioni. Questo è il numero m punti a mutex_ che non esiste più dopo l'eliminazione. La tua migliore scommessa potrebbe essere fare mutex_ statico.

Edit: Sebbene mutex_ punta a una variabile esterna che continua ad esistere dopo che la classe viene eliminato, non v'è alcuna garanzia a prova di proiettile che il compilatore non rinviare alla mutex_ dopo che la classe viene eliminato per ottenere il valore della mutex esterno. C'è una buona possibilità che le cose funzionino come previsto, ma non credo che questo possa essere garantito.

+0

No, 'm' punta non a' mutex_' ma a qualsiasi cosa 'mutex_' punti: notate che' mutex_' è un riferimento stesso! –

+0

Vedere la mia modifica - Sto assumendo che un riferimento sia trattato come un puntatore ma essendo un riferimento, il compilatore può memorizzare nella cache il valore di mutex_ e fare in modo che le cose funzionino come previsto. – doron

+3

Se il compilatore fa ciò che si ipotizza potrebbe, è rotto. Questo è legale C++. Detto in altro modo - come questa situazione è diversa da 'int a = myIntegerMemberVariable_; cancella questo; doSomethingWith (a); '?Non è abbastanza chiaro in questo caso che qualsiasi compilatore che "ottimizza" questo in 'doSomethingWith (this-> myIntegerMemberVariable _);' è rotto? –

0

Sì in questo caso. La variabile dello stack 'm' punta a una risorsa esterna che si ottiene nel costruttore

1

Sì, è possibile, ma perché non utilizzare il decremento atomico invece di decrementare il contatore sotto il mutex? E hai effettivamente bisogno di proteggere (da mutex) la distruzione dell'oggetto? Infatti, dopo il contatore diventa 0, l'unico thread corrente può accedere all'oggetto.

Così, forse è possibile riscrivere il codice come

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

(o utilizzare Atomics per decrementare e testare il contatore)

+1

** Pericoloso **! Questo può raddoppiare poiché si prova per 'tmp_count <= 0'. Sarebbe sicuro testare per '== 0' invece. Ma questo esempio illustra in modo bello perché il codice concorrente è così difficile da ottenere. –

+0

È pericoloso se il programma contiene qualche altro bug (recount_ non può essere <0 altrimenti); ma generalmente sono d'accordo che == sia più accettabile in questo caso. +1 su codice simultaneo. Il tempo speso per analizzare e verificare tale codice potrebbe essere 10.20..50 volte maggiore del tempo speso per scriverlo. – user396672

Problemi correlati