2012-05-15 15 views
7

Digamos que tengo dos objetos locales. Cuando la función retorna, ¿se garantiza cuál saldrá primero del alcance?Orden y punto de llamada destructor

Por ejemplo:

tengo una clase como esta:

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

Este es un truco muy común que se utiliza para liberar automáticamente la exclusión mutua cuando se va fuera de alcance. Pero, ¿y si necesito dos mutexes en el alcance?

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? 

Esto realmente no puede causar ningún punto muerto. Pero puede haber instancias en las cuales el orden de liberación del recurso pueda ser útil para el usuario. En ese caso, ¿es importante ser explícito en lugar de confiar en los destructores?

Además, ¿puede la destrucción ser retrasada por el compilador en cualquier caso? Lo que quiero decir es

func() 

{ 

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

Respuesta

10

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

Los destructores serán llamados en el orden inverso al de la construcción: m2 continuación m1.

En ese caso, ¿es importante ser explícito en lugar de confiar en los destructores?

El orden de destrucción está bien especificado para que pueda confiar en él.

Además, ¿puede la destrucción ser retrasada por el compilador en cualquier caso?

No. Si así fuera, eso sería romper un montón de RAII código basado en (la clase MutexLock es un muy buen ejemplo de ello).

+1

Para sustentar la primera parte de la respuesta de @aix, este es un extracto del estándar (versión preliminar, Fecha: 2006-11-06 --- este aspecto no ha cambiado en versiones posteriores. Las referencias a las secciones se omiten para mayor claridad): "Al salir de un ámbito (no importa cuán logrado), se invocan destructores para todos los objetos construidos con duración de almacenamiento automático (objetos nombrados o temporales) que se declaran en ese ámbito, en el orden inverso al de su declaración". Por supuesto, su ejemplo implica declaraciones de variables automáticas. – sturmer

2

La destrucción ocurre en orden inverso de construcción: primero m2 luego m1.

El compilador nunca puede retrasar la duración del objeto detrás del end end (}).

0

El objeto siempre se destruye cuando se sale del alcance, esto no es java. f Será destruido donde indique y nunca será destruido al final de func. en general, los destructores se llaman en orden inverso al orden de su construcción.

4

En ese caso, ¿es importante ser explícito en lugar de confiar en los destructores?
No, no es obligatorio.
El orden de destrucción de objetos en un ámbito está bien definido.
Es exactamente opuesto al orden en que se construyeron.


Además, puede retrasarse la destrucción por el compilador, en cualquier caso?
No.
El compilador no puede y ese es el propósito de RAII. Proporciona el mecanismo para limpiar implícitamente & desasignar recursos sin ningún esfuerzo manual explícito por parte del programador.
Su requisito de retrasar la destrucción es paralelo al propósito de RAII, requiere manual de administración de recursos.
Si necesita administración manual de recursos puede tener punteros asignados en heap a través de new y los objetos apuntados por ellos serían válidos a menos y hasta que los desasigné explícitamente mediante la llamada delete y el orden en el que los llama.
Por supuesto, no es aconsejable ni recomendable hacerlo.