c++ - ¿Por qué los destructores no son virtuales por defecto
virtual-destructor (3)
¿Por qué C ++ no hace que los destructores sean virtuales de forma predeterminada 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. ¿C ++ 0x abordará esto?
Aquí hay 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 es un código perfectamente fino que no exhibe UB. Esto es posible porque std::shared_ptr
usa borrado de tipo; la llamada final a delete
eliminará un derived*
, incluso si el último std::shared_ptr
para desencadenar la destrucción es de tipo std::shared_ptr<void>
.
Tenga en cuenta que este comportamiento de std::shared_ptr
no está diseñado para la destrucción virtual; tiene una variedad de otros usos (por ejemplo, std::shared_ptr<FILE> { std::fopen( ... ), std::fclose }
). Sin embargo, debido a que esta técnica ya paga el costo de la indirección para que funcione, es posible que algunos usuarios no estén interesados en tener un destructor virtual para sus clases básicas. Eso es lo que significa " pagar solo por lo que necesita ".
No pagas por lo que no necesitas. Si nunca borra a través del puntero base, es posible que no desee la sobrecarga de la llamada del destructor indirecto.
Quizás estabas pensando que la mera existencia de la vtable es la única sobrecarga. Pero también se debe considerar cada despacho de función individual, y si quiero hacer el despacho de llamada de mi destructor directamente, se me debería permitir hacerlo.
Sería bueno para su compilador avisarle si alguna vez elimina un puntero base y esa clase tiene métodos virtuales, supongo.
Edición: Permítame extraer el excelente comentario de Simon aquí: Echa un vistazo a esta pregunta SO sobre el código generado para los destructores. Como puede ver, también hay que considerar la sobrecarga de código.
Por la letra del estándar, 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 resulta en un comportamiento indefinido, pero todo lo demás es perfectamente kosher. Entonces, dado el comportamiento indulgente de la norma en cuanto a los errores que permite a los programadores, ¿por qué se debe dar un tratamiento 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 a destructor.
Que yo sepa, no, no hay cambios en el comportamiento de los destructores a este respecto en C ++ 11. Me imagino que diría algo en la sección sobre funciones miembro especiales, pero no lo hace, y tampoco hay nada similar en la sección de funciones virtuales en general.