25

Éste me hizo pensar:Eliminar objetos de tipo incompleto

class X; 

void foo(X* p) 
{ 
    delete p; 
} 

¿Cómo podemos delete p si no incluso saber si tiene X destructor visible? g ++ 4.5.1 da tres advertencias:

warning: possible problem detected in invocation of delete operator: 
warning: 'p' has incomplete type 
warning: forward declaration of 'struct X' 

Y luego dice:

nota: ni el destructor ni el operador específico de clase eliminar serán llamados, incluso si se declaran cuando se define la clase.

Wow ... ¿se necesitan compiladores para diagnosticar esta situación como lo hace g ++? ¿O es un comportamiento indefinido?

+0

¡gracioso, encontré esto ayer! – UncleZeiv

+0

Solo para obtener información: Visual C++ 9.0 muestra dicha advertencia también ... – cybevnm

+0

posible duplicado de [¿Por qué, realmente, borrar un tipo incompleto es un comportamiento indefinido?] (Http://stackoverflow.com/questions/2517245/why-really- deleting-an-incomplete-type-is-undefined-behavior) – fredoverflow

Respuesta

20

de la norma [expr.delete]:

Si el objeto que está siendo borrada tiene tipo de clase incompleta en el punto de deleción y la clase completa tiene un destructor no trivial o una desasignación función, el comportamiento es undefined.

Por lo tanto, es UB si hay cosas no triviales que hacer, y está bien si no es así. Las advertencias no son necesarias para UB.

+2

No, no es "UB if", es UB incondicional. Por ejemplo, esa clase podría tener 'operator new' sobrecargado en un montón separado y la declaración' delete' ahora llamará 'operator delete' incorrecto. – sharptooth

+6

Acaricié la parte ambigua. Hasta donde puedo ver, el estándar no dice que eliminar objetos de tipo incompleto es UB en todos los casos, tal como se menciona en la sección que cité. ¿Por qué crees que es UB incondicionalmente? (¿Dónde dice esto el estándar?) – etarion

+1

@etarion: El estándar dice que el comportamiento dependerá de cómo se declare esa clase, lo que significa que puede comenzar con una clase que satisfaga esos requisitos y luego cambiarla para no satisfacer esos requisitos y ahora usted cara UB (que puede ser "funciona" por cierto).Entonces, aunque formalmente estás limpio, has sembrado un error fatal en tu código. La advertencia en cuestión debe abordarse: "eliminar" clases incompletas es una muy mala idea. – sharptooth

3

Es un comportamiento indefinido, y un problema común cuando se implementa el patrón pImpl. Que yo sepa, simplemente no existe una advertencia que el compilador debe emitir. Las advertencias son electivas; están ahí porque el escritor del compilador pensó que serían útiles.

5

Es un comportamiento indefinido.

Sin embargo, se puede hacer el registro de entrada del compilador para este tipo incompletas, como impulso:

// verify that types are complete for increased safety 

template<class T> inline void checked_delete(T * x) 
{ 
    // intentionally complex - simplification causes regressions 
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; 
    (void) sizeof(type_must_be_complete); 
    delete x; 
} 

Aplicando sizeof a un tipo incompleto deben dar lugar a un error, y supongo que si eso pasa con algún compilador, a continuación, una serie de tamaño negativo desencadenaría un error.

Cuestiones relacionadas