2010-08-06 16 views
7

Tengo una clase que emplea un mecanismo de recuento de referencias. Los objetos de esta clase se destruyen eventualmente llamando al delete this cuando el recuento de referencia cae a cero. Mi pregunta es: ¿puedo usar la variable local en la pila después de delete this? Aquí hay un ejemplo más específico:Acceder a una variable local después de "eliminar esto"

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

tener objetos contarse es una mala idea (¿Puede decir si es una variable de vida estática (pila) o vida útil dinámica (montón). Así es como funciona COM y de las experiencias adquiridas por la comunidad C++ hemos avanzado, como se puede ver en boost :: shared_ptr donde el recuento de referencia es no es parte del objeto que se está considerando. –

+0

@MartinYork Estoy de acuerdo contigo. En un caso general, no me aconsejaría implementar tales recuento de referencia. Este es un caso especial sin embargo. Afortunadamente, en mi situación real, el constructor no es público y la creación está protegida por un objeto de fábrica. – FireAphis

Respuesta

7

, you may do this, , siempre y cuando la variable miembro de sí mismo es en realidad sólo una referencia a un objeto externo.

(Por favor, perdona la respuesta equivocada anterior, estaba confundido acerca de la variable mutex_.)

+0

+1 de mí. Pasé por alto lo que se asignó a la variable local. Me gusta más tu respuesta, así que borré la mía. – Manfred

0

En general, el único que no se le permite llamar después delete this es todo lo que hace referencia a this. Esto incluye cualquier miembro o función de clase no estática.

En su caso, existe una buena posibilidad de que RemoveReference no funcione. Esto se debe a m puntos a mutex_ que ya no existe después de eliminar esto. Su mejor opción podría ser hacer que mutex_ estético.

Editar: Aunque mutex_ apunta a una variable externa que continúa existiendo después de eliminar la clase, no hay garantía de balas que el compilador no se referirá a mutex_ después se elimina la clase para obtener el valor de la mutex externo Existe una buena posibilidad de que las cosas funcionen como se esperaba, pero no creo que esto pueda garantizarse.

+0

No, 'm' apunta a' mutex_' pero a cualquier punto 'mutex_': ¡advierte que' mutex_' es una referencia en sí misma! –

+0

Ver mi edición - Estoy suponiendo que una referencia se trata como un puntero pero al ser una referencia, el compilador puede almacenar en caché el valor de mutex_ y hacer que las cosas funcionen como se esperaba. – doron

+3

Si el compilador hace lo que especula que podría ser, está roto. Esto es legal C++. Dicho de otra manera: cómo esta situación es diferente a 'int a = myIntegerMemberVariable_; borrar esto; doSomethingWith (a); '?¿No está bastante claro en este caso que cualquier compilador que "optimice" esto para 'doSomethingWith (this-> myIntegerMemberVariable _);' está roto? –

0

Sí en este caso. Su variable de pila 'm' apunta a un recurso externo que usted obtiene en el constructor

1

Sí, puede hacerlo, pero ¿por qué no usar decremento atómico en lugar de decrementar el contador bajo el mutex? ¿Y realmente necesitas proteger (mediante mutex) la destrucción de objetos? De hecho, después de que el contador se convierte en 0, el único hilo actual puede acceder al objeto.

Por lo tanto, tal vez es posible reescribir su código como

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

(o uso atómica para disminuir y probar el contador) Referencia

+1

** ¡Peligroso **! Esto puede eliminarse por duplicado ya que prueba 'tmp_count <= 0'. Sería seguro probar por '== 0' en su lugar. Pero este ejemplo ilustra bellamente por qué el código concurrente es tan difícil de corregir. –

+0

Es peligroso si el programa contiene alguna otra falla (el recuento_ no puede ser <0 en caso contrario); pero generalmente estoy de acuerdo en que == es más aceptable en este caso. +1 sobre el código concurrente. El tiempo invertido para analizar y verificar dicho código puede ser 10 ... 20 ... 50 veces mayor que el tiempo que se tarda en escribirlo. – user396672

Cuestiones relacionadas