El compilador GNU advierte que "la clase tiene funciones virtuales pero un destructor no virtual"

StackOverflow https://stackoverflow.com/questions/127426

  •  02-07-2019
  •  | 
  •  

Pregunta

He definido una interfaz en C++, es decir.una clase que contiene sólo funciones virtuales puras.

Quiero prohibir explícitamente a los usuarios de la interfaz eliminar el objeto a través de un puntero a la interfaz, así que declaré un destructor protegido y no virtual para la interfaz, algo como:

class ITest{
public:
    virtual void doSomething() = 0;

protected:
    ~ITest(){}
};

void someFunction(ITest * test){
    test->doSomething(); // ok
    // deleting object is not allowed
    // delete test; 
}

El compilador GNU me da una advertencia que dice:

la clase 'ITest' tiene funciones virtuales pero un destructor no virtual

Una vez protegido el destructor, ¿cuál es la diferencia entre tenerlo virtual o no virtual?

¿Cree que esta advertencia se puede ignorar o silenciar con seguridad?

¿Fue útil?

Solución

Es más o menos un error en el compilador.Tenga en cuenta que en versiones más recientes del compilador esta advertencia no aparece (al menos en 4.3 no aparece).Que el destructor esté protegido y no sea virtual es completamente legítimo en su caso.

Ver aquí por un excelente artículo de Herb Sutter sobre el tema.Del artículo:

Pauta #4:Un destructor de clase base debe ser público y virtual o protegido y no virtual.

Otros consejos

Algunos de los comentarios sobre esta respuesta se relacionan con una respuesta anterior que di, que era incorrecta.

Un destructor protegido significa que solo se puede llamar desde una clase base, no mediante eliminación.Eso significa que un ITest* no se puede eliminar directamente, solo una clase derivada puede hacerlo.Es posible que la clase derivada necesite un destructor virtual.No hay ningún problema con tu código.

Sin embargo, dado que no puede deshabilitar localmente una advertencia en GCC y ya tiene una vtable, podría considerar hacer que el destructor sea virtual de todos modos.Le costará 4 bytes por programa (no por instancia de clase), como máximo.Dado que es posible que le haya dado un médico virtual a su clase derivada, es posible que descubra que no le cuesta nada.

Si insistes en hacer esto, adelante y pasa. -Wno-non-virtual-dtor al CCG.Esta advertencia no parece estar activada de forma predeterminada, por lo que debes haberla habilitado con -Wall o -Weffc++.Sin embargo, creo que es una advertencia útil, porque en la mayoría de las situaciones esto sería un error.

Es una clase de interfaz, por lo que es razonable que no elimine objetos que implementen esa interfaz a través de esa interfaz.Un caso común de esto es una interfaz para objetos creados por una fábrica que deben devolverse a la fábrica.(Hacer que los objetos contengan un puntero a su fábrica puede resultar bastante caro).

Estoy de acuerdo con la observación de que GCC se está quejando.En cambio, simplemente debería advertirle cuando elimine un ITest*.Ahí es donde reside el verdadero peligro.

Mi opinión personal es que estás haciendo lo correcto y el compilador no funciona.De ser posible, desactivaría la advertencia (localmente en el archivo que define la interfaz).

Creo que uso bastante este patrón ('p' pequeña).De hecho, encuentro que es más común que mis interfaces tengan controladores protegidos que públicos.Sin embargo, no creo que sea un modismo tan común (no se habla mucho de él) y supongo que cuando se agregó la advertencia a GCC era apropiado intentar y hacer cumplir que el 'dtor anterior debe ser virtual si tener la regla de funciones virtuales.Personalmente actualicé esa regla a 'dtor debe ser virtual si tiene funciones virtuales y desea que los usuarios puedan eliminar instancias de la interfaz a través de la interfaz; de lo contrario, el dtor debe estar protegido y no ser virtual' hace años;)

Si el destructor es virtual, se asegura de que el destructor de la clase base también se llame antes de realizar la limpieza; de lo contrario, pueden producirse algunas fugas a partir de ese código.Por lo tanto, debe asegurarse de que el programa no tenga este tipo de advertencias (preferiblemente ninguna advertencia).

Si tuvieras código en uno de ITestLos métodos que intentaron delete en sí (una mala idea, pero legal), no se llamaría al destructor de la clase derivada.Aún así debes hacer que tu destructor sea virtual, incluso si nunca tienes la intención de eliminar una instancia derivada a través de un puntero de clase base.

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