2011-02-01 21 views
6

De ejemplos que he visto COM IUnknown::Release() implementación de la función es algo así:¿Por qué funciona esta implementación de COM IUnknown :: Release?

ULONG Release() 
{ 
    InterlockedDecrement(&m_count); 
    if(m_count == 0) { 
     delete this; 
    } 
    return m_count; 
} 

lo tanto, si m_count es 0, por lo que estamos eliminando objeto "this", y devolver el recuento de ref. Lo que no entiendo es por qué funciona?!?!

  1. eliminar el objeto no arruinaría la pila de llamadas o ¿es correcto porque está siendo realizado por el flujo, por lo que no tiene nada que ver con el objeto ???

  2. Si el objeto se ha eliminado, ¿cómo es posible que podamos devolver m_count, debería haberse eliminado? Podría haberme convencido a mí mismo de que está bien si después de la eliminación, el código devuelve un código fijo de 0, pero ¿cómo puede devolver el miembro?!?!

¡Muchas gracias por su ayuda! :-)

+1

+1 Tienes razón, o bien es un código defectuoso o hay algo más matizado en el trabajo aquí. Tengo curiosidad si alguien con más experiencia con COM puede responder a esto, pero mi punto culminante es que esto es totalmente erróneo. – templatetypedef

Respuesta

15

Ese código es falso. Uno nunca puede confiar en m_count después de la disminución. El código correcto es siempre así:

ULONG Release() 
{ 
    ULONG count = InterlockedDecrement(&m_count); 
    if(count == 0){ delete this; } 
    return count; 
} 
+0

¿Quisiste decir "** after ** the * delete *"? –

+2

No, quiso decir después de la disminución. Si hay varios hilos accediendo a esto, es posible que otro hilo también llame a Release, haciendo que el valor de la variable miembro sea negativo si se hace entre el decremento y el condicional. –

+6

No, realmente quiero decir después del 'Decremento'. El problema de desreferenciar 'this' después de' delete' es obvio y no necesita repetirse. Pero hay un problema más sutil de concurrencia. Su disminución podría llevar el recuento a, digamos, 2. Para el momento en que toque m_count nuevamente, dado que ya ha liberado su conteo, * otros hilos podrían haber llegado a 0 y haber liberado el objeto, y el intervalo podría haberse reasignado incluso a algo más. No toque m_count después del Decremento * hic sunt leones *. –

1

Lo que observamos es un comportamiento indefinido. La pila de llamadas no se cambia por delete this; y delete this by itself is always safe, sino renders this pointer invalid, lo que significa que ya no puede desreferenciarla.

Hay dos posibles explicaciones de lo que observa. O la implementación en cuestión simplemente no desreferencia this puntero para obtener m_count al regresar de la función - lo tiene cargado en un registro y solo usa ese valor y por lo tanto this no se desreferencia y no observa ningún problema o delete finaliza la memoria ocupada por el objeto que todavía está mapeada en el espacio de direcciones del proceso y permanece técnicamente accesible, por lo que la eliminación de referencias this se realiza correctamente y m_count se lee con éxito. Supongo que este último es más probable.

Cualquiera que sea la explicación de ese comportamiento indefinido, no puede confiar en eso, use lo que user Remus Rusanu sugiere in his answer.

Cuestiones relacionadas