2009-12-07 10 views
19

Estaba leyendo este article y queríamos así que la gente consejo:¿Debería llamarse "eliminar esto" desde un método miembro?

Q: En caso de delete this; ser llamado desde dentro de un método miembro?

+7

Una mejor pregunta: "Si alguna vez uso 'eliminar este'"? Respuesta - no. –

+13

En raras ocasiones es apropiado llamar a "eliminar esto", pero son muy raras ... –

+2

@Neil: no se puede usar 'eliminar esto' en ninguna otra parte que no sea una función miembro (o un inicializador en un constructor, Supongo, pero eso solo me duele el cerebro). Entonces deberías publicarlo como una respuesta. –

Respuesta

33

Normalmente, esta es una mala idea, pero a veces es útil.

Es perfectamente seguro siempre que no utilice variables miembro después de eliminar, y siempre que los clientes que llamen a este método entiendan que puede eliminar el objeto.

Un buen ejemplo de que esto es útil es si la clase emplea el recuento de referencias:

void Ref() { 
    m_References++; 
} 

void Deref() { 
    m_References--; 
    if (m_References == 0) { 
    delete this; 
    } 
} 
+3

¿cómo deletreas "punteros colgantes"? – elcuco

+16

Acabas de deletrear bien, Elcuco. ¿Cual es tu punto? ¿Tienes miedo de que un objeto se destruya a sí mismo creando punteros más colgantes de los que habría si algo más destruyera el objeto? 'foo-> Deref()' no es peor que 'if (foo-> Deref() == 0) delete foo;'. Además, si el recuento de referencia es cero, entonces no hay ningún otro puntero que se deje colgando de todos modos. –

1

No sin una muy buena razón para hacerlo.

El problema es que cuando llama al delete this en una función de miembro, está creando un desagradable efecto secundario: la persona que llama todavía tiene una referencia a su instancia que ahora es completamente inválida.

Esto probablemente no es un comportamiento esperado, por lo que podría conducir fácilmente a errores desagradables.

Dicho esto, hay ocasiones en que esto es apropiado (he visto algunos esquemas de administración de memoria, con ciertas bibliotecas, donde se crean explícitamente métodos en las clases que se eliminan, principalmente para la interoperabilidad del lenguaje). En general, creo que es una mala práctica, sin embargo.

12

Creo que en realidad hay 2 preguntas aquí

puede eliminar este ser llamados de forma válida de un método miembro ?

Sí. Esto es legal siempre que sea muy cuidadoso con el uso.

¿Debería eliminar esto utilizando un método de miembro?

En casos muy específicos, esto es necesario. Ciertos tipos de punteros inteligentes, por ejemplo, usan el patrón delete this para matar el puntero. Ejemplos: CComPtr<> estilo.

Sin embargo, aparte de los indicadores inteligentes, debe evitarse a menos que tenga una muy buena razón para hacerlo. Incluso entonces, reconsideraría cuidadosamente mi escenario y vería si había una forma de evitarlo.

5

Sí, hay algunos casos en que es común.

conteo de referencia:

void release() 
{ 
    cnt--; 
    if (cnt == 0) 
    delete this; 
} 

programación de interfaz gráfica de usuario. En algunos marcos, cuando un usuario cierra una ventana, es común que la ventana se elimine a sí misma.

11

Sí se puede y here's una buena explicación de cuándo y por qué

+1

O aquí hay un enlace que explica el peligro y la lectura entre líneas de por qué no debería hacerlo. –

0

Puede hacerlo, siempre que tenga el último elemento de una función miembro, y que después de la vuelta que olvidar que alguna vez existió objeto .... pero Sí, como ese artículo pregunta ... ¿Por qué querrías hacer esto?No sé lo que dice el estándar, pero me da una sensación graciosa: P

Supongo que esto es un poco como debería usar una declaración GOTO, y yo personalmente uso GOTO para limpiar los recursos en C a veces, especialmente bajo condiciones excepcionales.

Me pregunto cuáles son las implicaciones del estado son compartidos (declaración difusa lo sé): P

1

Algunas bibliotecas de roscado utilizan en la aplicación de un auto destruye a la terminación hilo.

void Thread::threadFunc() 
{ 
    doRun(); 

    if(this->destroyOnExit == true) 
     delete this; 
} 
1

Esto se solía usar en los días de MFC. IIRC el último mensaje recibe una ventana es WM_NCDESTROY, momento en el que se podría llamar delete this, suponiendo que fueras algún tipo de sádico, por supuesto (aunque sí MFC hizo esto, a veces, creo.)

+1

Sí, la función MFC OnDestroy() lo hace :) –

5

Preparándose para los votos hacia abajo.

en caso de que: Nº
¿Puede Técnicamente: Sí
¿Es una buena idea: Por supuesto que no.
¿Hay alguna situación útil: Por supuesto. Si eres C++ foo es extremadamente fuerte. Pero la mayoría de la gente no es tan buena. Solo haga esto si tiene un equipo de personas trabajando con usted que pueda hacer una revisión de código decente.

Por qué:
No hay forma de que un objeto de saber que se ha asignado dinámicamente (y por lo tanto necesita borrar) o es un objeto normal (y por lo tanto no debe ser borrada) y por lo tanto ¿cómo puede decidide el clima debe ser eliminado. Por lo tanto, si un objeto se borra a sí mismo, en mi opinión, hay algo terriblemente mal con el diseño.

Si tiene un objeto que necesita administrar, debe escribir un objeto seprate para hacer la gestión (por lo tanto, punteros inteligentes). Deje que el objeto haga lo que es bueno, luego separe la administración del objeto en otro objeto.

+0

También tenga en cuenta que "fuera de la clase" aún no puede estar seguro de que un puntero realmente apunta a un objeto asignado dinámicamente y no a un objeto automático o estático, por ejemplo. (De hecho, creo que en muchos casos puede estar aún menos seguro que en la función miembro ...) Entonces 'eliminar p' es arriesgado independientemente de si' p' es 'this' o no. –

+0

@ Adam: Gracias. Pero como se señaló, "puede" ser útil. Pero en C++ moderno se considera una mejor práctica separar la gestión del objeto de la implementación del objeto (por lo tanto, ahora se usan punteros inteligentes en lugar de COM). También tenga en cuenta que un objeto de gestión puede beneficiarse fácilmente de que el objeto que administra se asigna dinámicamente, por lo que es completamente un premisa falsa. –

0

Sí. Como dicen todas las respuestas, si está 100% seguro de que los datos de la clase no se usarán después de que se llame al delete this.

Por ejemplo, en un proyecto:

void Test() 
MyClass * Someclass = new MyClass; 
SomeClass->DoYourThing(); 
SomeClass->KillYourself(); 
return; 

void MyClass::DoYourThing() { return; } 
void MyClass::KillYourself() {delete this;} 

explicación muy simplista, el proyecto utilizó delete this; como parte de la gestión de memoria para objetos de ese tipo; su constructor los agregó a una lista privada de clases de ese tipo en uso, y se eliminaron de esa lista cuando se destruyeron y luego se eliminaron ellos mismos (esto no estaba en un destructor). Todos los objetos de esa clase que no se habían suprimido sí mismos cuando el programa llegó a su punto final entonces todos tenían su equivalente KillYourself() llama de una función miembro estática CleanYourselves()

0
  1. delete this no puede ser llamado de una función no miembro :)
  2. Es una mala idea hacerlo hasta que comprenda sus consecuencias.
0

Aunque no directamente relacionado con este hilo, quería aclarar esto. Me hicieron una pregunta que, dada una situación:

int* a = new int ; 
int* b = a ; 
delete a; 

Ahora es el próximo estado seguro?

cout<<*b ;

Mi respuesta: Después de eliminar una, la ubicación apuntada por un se ha marcado para su eliminación y en cualquier punto de tiempo que se puede asignar a algún otro objeto. Por lo tanto, acceder al valor usando b no es seguro, ya que puede modificarse después de haber sido asignado a algún otro objeto.

Nota: No se downvoting por favor, esto es sólo una aclaración

Cuestiones relacionadas