2014-07-24 9 views
5

Considerare seguente codiceQuando esattamente si chiama il distruttore in C++

int i; 

class A 
{ 
public: 
    ~A() 
    { 
     i=10; 
    } 
}; 

int foo() 
{ 
    i=3; 
    A ob; 
    return i; 
} 

int main() 
{ 
    cout << foo() << endl; 
    return 0; 
} 

Dal i è globale, ho pensato che l'uscita di questo programma dovrebbe essere 10. ob, quando esce dall'ambito chiamerà il distruttore che dovrebbe impostare il valore di i a 10.

+5

La parentesi '}' genera molto codice in C++ :) –

+0

@HansPassant Mai fidarsi di una lingua in cui la parola chiave "blocco finale" è a sua volta Turing completa. ;-) – Sneftel

risposta

4

ob esce dallo scope dopo l'esecuzione del ritorno. Considerare cosa accadrebbe se ob fosse coinvolto nella valutazione dell'espressione di ritorno e sarebbe andato fuori portata prima del ritorno.

4

ob non esce dal campo di applicazione fino alla fine dell'ambito, vale a dire allo } che si verifica dopo l'istruzione return. Questo è il momento in cui viene chiamato il distruttore, ma per il momento i è già stato valutato, quindi viene restituito il vecchio valore.

15

Le variabili locali escono dall'ambito e i loro distruttori vengono eseguiti, dopo la funzione restituisce. Il che significa che quando viene eseguito il periodo ~A(), il valore restituito è già 3. Al contrario, se avete fatto queste cose ...

int foo() 
{ 
    { 
     i=3; 
     A ob; 
    } 
    return i; 
} 

... ob farebbe di portata e muoiono prima l'istruzione return, e il risultato sarebbe 10.

ambiti extra sono spesso utilizzati questo modo con tipi attivi RAII come scoped_lock, per entrare in un particolare stato di effetto collaterale solo per una parte di una funzione.

6
int foo() 
{ 
    i=3; 
    A ob; 
    return i; 
} // <- ~A() is called here 

~A() è chiamato alla fine della funzione foo(), quando ob passa nell'ambito. Ciò avviene dopo aver calcolato il valore di ritorno (ad esempio una copia di i, con il valore di 3 in quel momento).

Per impostareda impostare su 10 prima che la funzione esca, è necessario forzare ob a uscire "fuori ambito in precedenza". Il più semplice è aggiungere uno scope aggiuntivo intorno a A ob.

int foo() 
{ 
    i=3; 
    { 
    A ob; 
    } // <- ~A() is called here and sets i to 10 
    return i; 
} 
3

Il ~A() viene chiamato quando ob passa nell'ambito. Assemblea prova:

<__Z3foov>: 
    push %ebp 
    mov %esp,%ebp 
    push %ebx 
    sub $0x10,%esp 
    movl $0x3,0x407020  /* <-- setting i to 3 */ 
    mov 0x407020,%ebx  /* <-- loading i to %ebx */ 
    lea -0x5(%ebp),%eax 
    mov %eax,%ecx 
    call 403860 <__ZN1AD1Ev> /* <-- calling destructor */ 
    mov %ebx,%eax   /* <-- returnign already calculated i from %ebx */ 
    add $0x10,%esp 
    pop %ebx 
    pop %ebp 
    ret 

<__ZN1AD1Ev>:    /* <-- the destructor */ 
    push %ebp 
    mov %esp,%ebp 
    sub $0x4,%esp 
    mov %ecx,-0x4(%ebp) 
    movl $0xa,0x407020 /* <-- set i to 10 */ 
    leave 
    ret 

Come si può vedere, il distruttore è chiamato dopo che il valore di ritorno è messo a %ebx, che è di nuovo spostato %eax quando distruttore è fatto. Per le tue future domande sul comportamento del codice C++, lo smontaggio è il tuo migliore amico.

Problemi correlati