Pregunta

¿Cómo es posible que se permita eliminar un objeto con un destructor privado en el siguiente código? He reducido el programa real al siguiente ejemplo, pero aún así se compila y funciona.

class SomeClass;

int main(int argc, char *argv[])
{
  SomeClass* boo = 0; // in real program it will be valid pointer
  delete boo; // how it can work?

  return -1;
}

class SomeClass
{
private:
  ~SomeClass() {}; // ! private destructor !
};
¿Fue útil?

Solución

Está intentando eliminar un objeto de tipo de clase incompleta. C ++ Standard dice que obtendrá un comportamiento indefinido en este caso (5.3.5 / 5):

  

Si el objeto que se está eliminando tiene un tipo de clase incompleto en el momento de la eliminación y la clase completa tiene un destructor no trivial o una función de desasignación, el comportamiento no está definido.

Para detectar estos casos, puede usar impulso: : checked_delete :

template<typename T> 
inline void checked_delete( T* p )
{
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
    (void) sizeof(type_must_be_complete);
    delete p;
}

Otros consejos

Este código causa un comportamiento indefinido (UB). Es UB en C ++ para eliminar un objeto de tipo incompleto que tiene un destructor no trivial. Y en su código, el tipo SomeClass está incompleto en el punto de delete , y tiene un destructor no trivial. Los compiladores generalmente emiten una advertencia sobre esto, ya que en C ++ formalmente esto no es una violación de restricción.

Por lo tanto, estrictamente hablando, su código no "funciona". Simplemente compila y hace algo indefinido cuando se ejecuta.

El compilador simplemente no es necesario para detectar este error. La razón de esto es que esto podría estar perfectamente bien si su objeto tiene un destructor trivial . El compilador no tiene forma de saber qué tipo de destructor tendrá este tipo, por lo que no puede decir con seguridad si se trata de un error o no.

Debido a que el tipo SomeClass no se declara completamente al invocar operador delete .

Eliminar ese puntero es un comportamiento indefinido, pero en la práctica, la mayoría de los compiladores simplemente liberarían la memoria (si el puntero no fuera NULL) y no llamaran al destructor.

Por ejemplo, g ++ te dará una advertencia sobre este problema:

foo.cpp: In function 'int main(int, char**)':
foo.cpp:6: warning: possible problem detected in invocation of delete operator:
foo.cpp:5: warning: 'boo' has incomplete type
foo.cpp:1: warning: forward declaration of 'struct SomeClass'
foo.cpp:6: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top