2011-07-08 21 views
23

¿Por qué C++ no hace que los destructores sean virtuales por defecto para las clases que tienen al menos otra función virtual? En este caso, agregar un destructor virtual no me cuesta nada, y no tener uno es (¿casi?) Siempre un error. ¿Va a abordar C++ 0x esto?Por qué los destructores no son virtuales de forma predeterminada [C++]

+2

La palabra clave es 'casi'. Si su base tiene funciones virtuales y no quiere pagar por el destructor virtual, ¿cómo se especifica que no es virtual en este nuevo mundo? ¿Qué pasa con todo el código anterior? Necesitamos un plan para tratar los problemas de compatibilidad con versiones anteriores. –

+4

El destructor virtual tiene un costo, ya que requiere otra copia del código del destructor para todas las clases derivadas. Ver [esta pregunta] (http://stackoverflow.com/questions/6613870/gnu-gcc-g-why-does-it-generate-multiple-dtors/6614903). –

+0

posible duplicado de [¿Por qué no tiene todas las funciones como virtual en CPP] (http://stackoverflow.com/questions/6606657/why-not-have-all-the-functions-as-virtual-in-cpp) – iammilind

Respuesta

19

No paga lo que no necesita. Si nunca lo borra a través del puntero base, es posible que no desee la sobrecarga de la llamada al destructor indirectamente.

Quizás estaba pensando que la mera existencia del vtable es el único gasto general. Pero también se debe considerar el envío de cada función individual, y si quiero hacer mi despacho de llamadas al destructor directamente, debería poder hacerlo.

Sería bueno de su compilador advertirle si alguna vez elimina un puntero base y esa clase tiene métodos virtuales, supongo.

Editar: Déjame sacar excelente comentario de Simon aquí: Salida this SO question en el código generado para los destructores. Como puede ver, también hay que considerar la sobrecarga de código.

2

Por la letra de la norma, una clase polimórfica con un destructor no virtual no es un error. Una acción específica realizada en un objeto de este tipo da como resultado un comportamiento indefinido, pero todo lo demás es perfectamente kosher. Entonces, dado el comportamiento, por lo demás indulgente, del estándar en términos de los errores que permite a los programadores, ¿por qué se le debe dar un trato especial al destructor?

Y tal cambio tendría costos, aunque en su mayoría triviales: la tabla virtual será un elemento más grande, y el despacho virtual asociado con las llamadas al destructor.

Según mi leal saber y entender, no, no hay ningún cambio en el comportamiento de los destructores a este respecto en C++ 11. Me imagino que diría algo en la sección sobre funciones especiales para miembros, pero no es así, y tampoco hay nada en la sección de funciones virtuales en general.

+0

¿Hubo * alguna vez * un plan para hacer que los destructores virtuales sean los predeterminados en C++ 0x? Lo pregunto porque me encontré con este artículo: http://www2.research.att.com/~bs/C++0x_panel.pdf que dice que había en la parte inferior, pero no he podido encontrar más información al respecto. – jeffythedragonslayer

+1

@dacode: No seguí las reuniones reales y otras cosas, así que no sé. De los cuatro "vergüenzas", solo el último fue realmente cambiado. No me sorprendería que alguien presentara una profecía para tal cambio, pero no puedo decir por qué fue rechazada. –

2

He aquí un ejemplo (no es que Recomiendo escribir dicho código):

struct base { 
    virtual void foo() const = 0; 
    virtual void bar() const = 0; 
}; 

struct derived: base { 
    void foo() const {} 
    void bar() const {} 
}; 

std::shared_ptr<base> 
make_base() 
{ 
    return std::make_shared<derived>(); 
} 

Este código es perfectamente bien que no presenta UB. Esto es posible porque std::shared_ptr usa borrado de tipo; la llamada final al delete eliminará un derived*, incluso si el último std::shared_ptr para desencadenar la destrucción es del tipo std::shared_ptr<void>.

Tenga en cuenta que este comportamiento de std::shared_ptr es no adaptado a la destrucción virtual; tiene una variedad de otros usos (por ejemplo, std::shared_ptr<FILE> { std::fopen(...), std::fclose }). Sin embargo, dado que esta técnica ya es paga el costo de algunas indirecciones, algunos usuarios pueden no estar interesados ​​en tener un destructor virtual para sus clases base. Eso es lo que "paga solo por lo que necesita" significa.

Cuestiones relacionadas