2012-05-15 18 views
7

Diciamo che ho due oggetti locali. Quando la funzione ritorna, è garantito quale sarà il primo a uscire dal campo di applicazione?Distruttore dell'ordine e del punto di chiamata

Ad esempio:

Ho una classe come questa:

class MutexLock 
{ 
    /* Automatic unlocking when MutexLock leaves a scope */ 
    public: 
     MutexLock (Mutex &m)  { M.lock(); } 
     ~MutexLock(Mutex &m)  { M.unlock(); } 
}; 

Questo è un trucco molto comune utilizzato per rilasciare automaticamente il mutex quando si va fuori del campo di applicazione. Ma cosa succede se ho bisogno di due mutex nell'ambito?

void *func(void *arg) 
{ 
    MutexLock m1; 
    MutexLock m2; 

    do_work(); 

} // m1 and m2 will get unlocked here. But in what order? m1 first or m2 first? 

Questo davvero non può causare alcun deadlock. Ma ci possono essere casi in cui l'ordine di rilascio della risorsa potrebbe essere utile all'utente. In tal caso è importante essere espliciti piuttosto che affidarsi ai distruttori?

Inoltre, la distruzione può essere ritardata dal compilatore in ogni caso? Quello che voglio dire è

func() 

{ 

    { 
     foo f(); 
    } ---------> Can compiler choose to not destroy f here, rather do it at the time when func() is returning. 
} 

risposta

10

// m1 and m2 will get unlocked here. But in what order? m1 first or m2 first?

I distruttori saranno chiamati in ordine inverso di costruzione: m2 poi m1.

In tal caso è importante essere espliciti piuttosto che affidarsi ai distruttori?

L'ordine di distruzione è ben specificato in modo da poter fare affidamento su di esso.

Inoltre, la distruzione può essere ritardata dal compilatore in ogni caso?

No. Se lo ha fatto, che sarebbe rompere un sacco di RAII codice basata su (la classe MutexLock è un ottimo esempio di quello).

+1

Per supportare la prima parte della risposta di @ aix, questo è un estratto dallo standard (versione bozza, Data: 2006-11-06 --- questo aspetto non è cambiato nelle versioni successive. Riferimenti alle sezioni omesse per chiarezza): "All'uscita da un ambito (comunque compiuto), i distruttori vengono chiamati per tutti gli oggetti costruiti con durata di archiviazione automatica (oggetti o temporali denominati) dichiarati in tale ambito, nell'ordine inverso della loro dichiarazione." Ovviamente il tuo esempio riguarda dichiarazioni di variabili automatiche. – sturmer

2

La distruzione avviene in ordine inverso di costruzione: prima m2 quindi m1.

Il compilatore non può mai ritardare la durata dell'oggetto dietro la fine dello scopo (}).

0

L'oggetto viene sempre distrutto quando esce dallo scope - non è java. f Verrà distrutto dove si indica e non verrà mai distrutto alla fine di func. in generale i distruttori sono chiamati in ordine inverso all'ordine della loro costruzione.

4

In tal caso è importante essere espliciti anziché fare affidamento sui distruttori?
No, non è necessario.
L'ordine di distruzione degli oggetti in un ambito è ben definito.
È l'esatto opposto dell'ordine in cui sono stati costruiti.


Inoltre, può essere ritardata distruzione dal compilatore, in ogni caso?

Il compilatore non può e questo è lo scopo di RAII. Fornisce il meccanismo per pulire implicitamente & deallocate risorse senza alcuno sforzo manuale esplicito su parte del programmatore.
Il tuo requisito di ritardare la distruzione è parallelo allo scopo stesso di RAII, richiede la gestione delle risorse manuale.
Se è necessaria la gestione manuale delle risorse, è possibile assegnare i puntatori su heap tramite new e gli oggetti da essi indicati saranno validi a meno che e fino a quando non vengano esplicitamente deallocati tramite la chiamata delete e l'ordine in cui vengono chiamati.
Ovviamente, non è consigliabile né incoraggiato a farlo.

Problemi correlati