2010-02-22 11 views
5

Actualmente estoy estudiando COM y el siguiente código me confundió.¿Cómo podría un método miembro eliminar el objeto?

STDMETHODIMP _(ULONG) ComCar::Release() 
{ 
    if(--m_refCount==0) 
    delete this; // how could this "suicide" deletion be possible? 
    return m_refCount; 
} 

Me pregunto cómo podría ser posible eliminar una instancia de objeto dentro de su método de miembro? Así que hice el siguiente experimento:

class A 
{ 
public: 
    void Suicide(void); 
    void Echo(void); 
    char name; 
}; 

void A::Echo(void) 
{ 
    ::printf("echo = %c\n",name); 
} 

void A::Suicide(void) 
{ 
    delete this; 
} 

int main(void) 
{ 
    A a; 
    a.name='a'; 
    a.Suicide(); //failed 
} 

Y la ejecución lo hace fracasado en a.Suicide(). El informe de depuración dice "Falló la aserción de depuración". ¿Podría alguien arrojar algo de luz sobre mí? Porque soy totalmente novato en COM.

Un hilo relacionado es aquí: Question about COM Release() method

Respuesta

10

cambiar su cuerpo de principal a:

A* a = new A(); 
a->name='a'; 
a->Sucide(); 

Puede eliminar sólo lo que fue construido por new, por supuesto - no hace ninguna diferencia si que se elimina está en una función miembro o en otro lugar.

7

En su ejemplo, Suicide() falla porque está llamando a eliminar en un objeto que no se ha asignado dinámicamente, lo cual no es válido independientemente de si la función llamante es miembro o no.

Las funciones miembro puede deletethis - si conocen el puntero this se ha asignado dinámicamente (a través de new). Sin embargo, no pueden acceder a los miembros después de ese punto, por lo que en rigor el ejemplo que diste:

STDMETHODIMP _(ULONG) ComCar::Release() 
{ 
    if(--m_refCount==0) 
    delete this; // how could this "sucide" deletion be possible? 
    return m_refCount; 
} 

resulta en un comportamiento no definido en la declaración return.

+3

Y la solución simple es simplemente devolver 0, por supuesto. – GManNickG

+0

Gracias, Michael, ya que mencionaste "alloacation dinámica", estoy adivinando si hay alguna "asignación estática" opuesta? ¿Qué es y cuál es la diferencia? quizás es difícil explicarlo en una palabra. ¿Podría darme alguna referencia para seguir estudiando? muchas gracias. : D – smwikipedia

+1

@GMan: Solo quiero aclarar que quiere decir: 'if (--m_refCount == 0) {eliminar esto; return 0; } return m_refCount; '. No puede simplemente cambiar la declaración de devolución para 'return 0;'. – Dan

1

Usa new para asignar un nuevo objeto de clase que vas a destruir llamando al delete.

2

No se puede eliminar un objeto que no se asignó dinámicamente. Los objetos COM se asignan dinámicamente.

Esto funciona:

#include <stdio.h> 

class A 
{ 
public: 
    void Sucide(void); 
    void Echo(void); 
    char name; 
}; 

void A::Echo(void) 
{ 
    ::printf("echo = %c\n",name); 
} 

void A::Sucide(void) 
{ 
    delete this; 
} 

void main(void) 
{ 
    A *a = new A; 
    a->name='a'; 
    a->Sucide(); // works 
} 
3

delete this es válida sólo cuando el objeto se asignó mediante el operador new. Para el recuento de referencias COM, esto no es inusual.

Sin embargo, hay otra advertencia: el acceso a las variables de miembro después de delete this no está definido, porque la memoria para el objeto ya se ha devuelto a la tienda gratuita. La primera muestra de código que publicó hace esto. Para solucionarlo, utilice una variable local:

STDMETHODIMP_(ULONG) ComCar::Release() 
{ 
    ULONG refCount = --m_refCount; 
    if(refCount==0) 
    delete this; 
    return refCount; 
} 
+1

Personalmente creo que es un poco más complicado, con la variable local. Si sabes que es cero dentro del enunciado if, simplemente devuelve 0. – GManNickG

+2

@GMan, pero luego necesitas dos declaraciones de devolución, una dentro del 'si' y otra afuera: el enfoque de bk1e guarda esa duplicación. –

+0

En lugar de duplicar la declaración de devolución, duplicamos el valor \ * shrug \ * Quizás esta sea más clara. – GManNickG

1

Hay una razón simple para esto. nuevo y eliminar debe coincidir.

Así que si crea un objeto en un dll y lo maneja a otra parte (exe, dll), el tiempo de ejecución de C podría ser diferente. En este caso, no puede llamar a eliminar porque el tiempo de ejecución no tiene conocimiento sobre el puntero que desea eliminar. Podría colapsar.

Debido a esto es un buen diseño para integrar el método del suicidio. En Com es un par de métodos.

AddRef 
Release 

lo que significa que el puntero tiene un contador para recordar cuántos propietarios tiene un objeto. Solo si el último propietario llama a eliminar, el objeto realmente se elimina.

Pero creo que hay un error en la implementación que ha publicado.

return m_refCount; 

no debe ser posible cuando se elimina el objeto. Al menos el comportamiento no está definido. Creo que debe almacenar m_refCount en una variable local para devolverlo en caso de eliminación.

STDMETHODIMP _(ULONG) ComCar::Release() 
{ 
    if(--m_refCount==0) { 
    delete this; // how could this "sucide" deletion be possible? 
    return 0; 
    } 
    return m_refCount; 
} 
Cuestiones relacionadas