Pregunta

Pocas horas atrás yo estaba jugando con un problema de pérdida de memoria y resultó que realmente tiene algunas cosas básicas sobre los destructores mal virtual! Permítanme decirlo de explicar mi diseño de la clase.

class Base
{
  virtual push_elements()
  {}
};

class Derived:public Base
{
vector<int> x;
public:
   void push_elements(){ 
      for(int i=0;i <5;i++)
         x.push_back(i); 
   }
};

void main()
{
    Base* b = new Derived();
    b->push_elements();
    delete b;
}

La herramienta límites corrector informó de una pérdida de memoria en el vector clase derivada. Y me di cuenta de que el destructor no es virtual y el destructor de la clase derivada no se llama. Y es sorprendente lo arreglaron cuando hice el destructor virtual. No es el vector desasigna automáticamente, incluso si el destructor de la clase derivada no se llama? Es que una peculiaridad en la herramienta BoundsChecker o es mi comprensión de mal destructor virtual?

¿Fue útil?

Solución

Eliminación de un objeto de la clase derivada a través de un puntero de clase base cuando la clase base no tiene un virtual cables destructor a un comportamiento indefinido.

Lo que ha observado (que la porción de la clase derivada del objeto nunca se destruye, por lo que sus miembros nunca se desasignado) es probablemente la más común de muchos de los comportamientos posibles, y un buen ejemplo de por qué es importante para asegurarse de sus destructores son virtuales cuando se utiliza el polimorfismo de esta manera.

Otros consejos

Si la clase base no tiene un destructor virtual, entonces el resultado de su código es un comportamiento indefinido, no necesariamente el destructor mal que se llama. Esto es presumiblemente lo BoundsChecker está diagnosticando.

A pesar de que esta no está definida técnicamente, todavía se necesita saber el método más común de fallo con el fin de diagnosticar. Ese método común de fallo es llamar al destructor mal. No sé de cualquier aplicación que se producirá un error en cualquier otra forma, aunque es cierto que yo sólo uso dos implementaciones.

La razón por la que esto sucede es la misma razón por la función 'mal' se llamará cuando se intenta reemplazar una función miembro no virtual y lo llaman a través de un puntero de base.

Si el destructor no es virtual a continuación, se llamará al destructor Base. El destructor de base limpia el objeto base y acabados. No hay forma de que el destructor objeto de base para saber sobre el objeto derivado, debe ser el destructor derivada llama, y ??la manera de hacer eso, al igual que con cualquier función, es hacer que el destructor virtual.

Desde el C ++ FAQ Lite: "¿Cuándo debe mi destructor ser virtual?" Leerlo aquí . (C ++ FAQ Lite es una excelente fuente para todas sus preguntas relacionadas con C ++, por cierto).

En C ++, una destructor trivial es un concepto de forma recursiva definida - es un destructor que el compilador escribió para que cuando todos los miembros de la clase (y cada clase base) tiene un destructor trivial. (Hay un concepto similar llamado el constructor trivial.)

Cuando un objeto con un destructor no trivial está incluido en un objeto (como el vector en su ejemplo), entonces el destructor del objeto fuera (como su Derived) en ya no es trivial. A pesar de que usted no lo hizo destructor de escritura, el compilador de C ++ escribió automáticamente un destructor que llama a los destructores de los miembros que tienen destructores.

Así que, a pesar de que usted no lo hizo nada de escritura, las advertencias de escribir un destructor no virtual se siguen aplicando.

Si usted viene de C #, a continuación, usted tenía razón en preguntarse por qué no se asigna automáticamente des-vectorial. Pero en C ++, gestión automática de memoria no es liviano menos que utilice el Microsoft Manged Extesions a C ++ (C ++ / CLI).

ya que no hay destructor de la clase base que es virtual, el objeto de la clase derivada nunca será liberado y no por tener fugas la memoria asignada para el miembro de datos de vectores de la la clase derivada.

Destructor es la función de miembro de la clase cuyo nombre es el mismo nombre del nombre de la clase y es precedido por el signo de tilde (~). Destructor se utiliza para destruir el objeto de la clase cuando el objeto sale del ámbito o se puede decir que toda la limpieza de la destrucción de clase han de ser hecho en destructor. Toda la memoria se asigna durante la construcción del objeto en la clase obtiene destruido (o la liberación de la memoria) cuando el objeto sale del ámbito.

Para más detalles con el ejemplo BoundsCheck

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top