2011-07-01 37 views
5

Después de pasar los últimos días depurando un subproceso múltiple donde un subproceso eliminaba un objeto que todavía estaba en uso por otro, me di cuenta de que el problema habría sido mucho más fácil y rápido de diagnosticar si hubiera podido hacer que 'esto' fuera volátil. Habría cambiado el volcado de emergencia en el sistema (sistema operativo Symbian) a algo mucho más informativo.¿Por qué 'esto' no es volátil?

Entonces, ¿hay alguna razón por la cual no puede ser o no debería ser?

Edit: Así que realmente no hay una manera segura de prevenir o verificar este escenario. ¿Sería correcto decir que una solución para acceder a punteros de clase obsoleta es tener una variable global que contenga el puntero, y las funciones que se llamen deberían ser estáticas que usen la variable global como reemplazo de 'esto'?

static TAny* gGlobalPointer = NULL; 

#define Harness static_cast<CSomeClass*>(gGlobalPointer); 

class CSomeClass : public CBase 
    { 
public: 
    static void DoSomething(); 

private: 
    int iMember; 
    }; 


void CSomeClass::DoSomething() 
    { 
    if (!Harness) 
     { 
     return; 
     } 

    Harness->iMember = 0; 
    } 

Por lo tanto, si se eliminara otro subproceso y NULL el puntero global, se detectaría inmediatamente.

Una cuestión que creo que con esto es que si el compilador guardó en caché el valor de arnés en lugar de comprobarlo cada vez que se utiliza.

+0

¿Quiere decir que habría sido más fácil si 'this' fuera volátil, o que hubiera sido más fácil si' this' fuera un puntero a volátil? En otras palabras, ¿veías en el volcado de emergencia un valor desactualizado de 'this' (que parece un poco extraño ya que nunca cambia), o de algún miembro de datos? –

Respuesta

7

esta no es una variable, sino una constante. Puede cambiar el objeto al que hace referencia este, pero no puede cambiar el valor de este. Como las constantes nunca cambian, no es necesario marcarlas como volátiles.

+1

Y por "constante" te refieres a 'T * const' y no a' const T * '. –

+2

La respuesta realmente no tiene sentido, en términos de C++. 'this' es una expresión. Y las expresiones 'const' ciertamente pueden cambiar en C++:' int x = 0; int const * px = & x; std :: cout << * px; x = 1; std :: cout << * px; '. – MSalters

+0

@Mike no, no quiere decir 'T * const' sino que significa' T * 'que no es un objeto. No tendría sentido hacer 'this'' const' tampoco. Bueno, al menos supongo que quiere decir. De lo contrario, su respuesta no tiene sentido para mí. –

2

Puede ser. Simplemente declare la función miembro como volátil.

struct a 
{ 
    void foo() volatile {} 
}; 
+1

Y para responder a la pregunta real, la razón por la que esto no ocurre por defecto es que no se podría pasar 'this' a una función que toma un puntero a no volátil. La misma razón 'this' no es un puntero-a-const a menos que marque la función miembro' const'. –

2

volátil no te ayudaría.
Haría que el acceso a una variable fuese volátil, pero no esperará a que se complete ningún método.

utilice punteros inteligentes.

shared_ptr

También hay una versión de ETS en las últimas versiones de C++.

+0

No hay punteros inteligentes en Symbian C++. No quería que proporcionara sincronización, quería que se bloqueara al acceder a un puntero antiguo. – James

+0

@James: Hacerlo volátil no lo conseguirá, desafortunadamente. –

+0

punteros compartidos son clases con componentes ... puede descargarlos y agregarlos a su proyecto –

4

No ayudaría: hacer que una variable sea volátil significa que el compilador se asegurará de que lea su valor de memoria cada vez que se acceda, pero el valor de this no cambia, incluso si, desde un contexto diferente o lo mismo, eliminas el objeto al que apunta.

+2

...porque borrar un puntero (específicamente, la memoria a la que apunta) no establece mágicamente el puntero a '0'. El compilador no tiene forma de saber dónde están todos los punteros a un objeto. –

+0

Si pudiera aceptar respuestas múltiples, lo haría. Gracias – James

0

Si el objeto se está leyendo mientras se está borrando, se trata de un claro error de memoria y no tiene nada que ver con volátil.

volátil está destinado a evitar que el compilador "recuerde" el valor de una variable en la memoria que puede ser modificada por un hilo diferente, es decir, impide que el compilador optimice.

p. Ej. si su clase tiene un miembro de puntero P y su método está accediendo a:

p->a; 
p->b; 

etc. yp es volátil dentro de "este" modo p->b puede obtener acceso a un objeto diferente de lo que era cuando lo hizo p->a

Si p ha sido destruido, ya que "this" fue eliminado, volátil no vendrá a tu rescate. Presumiblemente piensas que será "anulado" pero no lo será.

Dicho sea de paso, también es una regla bastante razonable que si su destructor bloquea un mutex para proteger otro hilo con el mismo objeto, tiene un problema. Su destructor puede bloquearse debido a que elimina su propia presencia de un objeto externo que necesita actividad síncrona, pero no para proteger a sus propios miembros.

Cuestiones relacionadas