2009-07-13 11 views
39

¿Se puede generar el destructor predeterminado como un destructor virtual automáticamente?¿Se puede generar el destructor predeterminado como un destructor virtual automáticamente?

Si defino una clase base pero no un destructor predeterminado, ¿hay un destructor virtual predeterminado generado automáticamente?

+0

por cierto, solo me pregunto, ¿qué es un destrutor predeterminado? ¿Hay más de un tipo de destructor? – user88637

+4

@ yossi1981: si no declaras un destructor en una clase, el compilador lo inserta. A riesgo de equivocarse con respecto a un caso inusual, este "destructor predeterminado" es el mismo que si hubiera definido "~ MyClass() {}". –

+3

@onebyone: para ser precisos: 'public: ~ MyClass() {}' - aunque los miembros de la clase son por defecto privados. – MSalters

Respuesta

37

No. Hay un costo asociado con hacer que un método sea virtual, y C++ tiene la filosofía de no hacer que pagues por cosas que no declaras explícitamente que deseas usar. Si un destructor virtual se hubiera generado automáticamente, habría pagado el precio automáticamente.

¿Por qué no definir un destructor virtual vacío?

+42

Tenga en cuenta que también puede hacer 'virtual ~ Foo() = default;' a partir de [C++ 11] (http://en.cppreference.com/w/cpp/language/member_functions#Special_member_functions) (si alguien está leyéndolo desde hace poco) – CoryKramer

+1

¿Qué costo adicional podría haber, si la clase tiene alguna otra función virtual? ¿Podría dar un ejemplo? – Spencer

+0

@Spencer: Llamar al destructor necesita la dirección del código d-tor que se resolverá en el tiempo de ejecución a través del vtable del objeto. Para los destructores no virtuales, la dirección del código se conoce en tiempo de compilación. –

1

No. Debe declararlo como virtual.

8

Uri y Michael son perfectos - voy a añadir que si lo está molestando que es tener que tocar dos archivos para declarar y definir el destructor, que está perfectamente bien para definir un mínimo de una línea en la cabecera:

class MyClass 
{ 
    // define basic destructor right here 
    virtual ~MyClass(){} 

    // but these functions can be defined in a different file 
    void FuncA(); 
    int FuncB(int etc); 
} 
+0

En realidad, creo que encontrará que cuando vincula esto, obtendrá una referencia indefinida a MyClass 'vtable. – keraba

+2

Solo obtendrá un error de "referencia indefinida a vtable" si está usando GCC y no define FuncA y FuncB no en línea, y eso es solo porque GCC no ha podido emitir todo lo necesario para permitir el correcto funcionamiento de GCC. enlace. –

+0

Estoy sorprendido por esto, ¿por qué esto causaría un problema de enlace? ¿Puede alguien elaborar? – Uri

9

No, todos los destructor son por defecto NO virtuales.

Usted tendrá que definir un destructor virtual en todas las clases base

Además de eso.

Para citar Scott Meyers en su libro "A partir del C++":

The C++ language standard is unusually clear on this topic. When you try to delete a derived class object through a base class pointer and the base class has a non-virtual destructor (as EnemyTarget does), the results are undefined

En la práctica, por lo general es una buena idea para definir una clase con un destructor virtual si usted piensa que alguien podría, finalmente, crear una clase derivada de eso. Tiendo a hacer que todas las clases tengan virtual destructor de todos modos. Sí, hay un costo asociado con eso, pero el costo de no hacerlo virtual más a menudo no supera un mísero bit de sobrecarga de tiempo de ejecución.

Sugiero que solo lo haga no virtual cuando esté absolutamente seguro de que lo desea de esa manera en lugar de confiar en el no virtual predeterminado que los compiladores aplican. Puede estar en desacuerdo, sin embargo (en resumen) Recientemente tuve una horrible pérdida de memoria en algún código heredado donde todo lo que hice fue agregar un std :: vector en una de las clases que había existido durante varios años. Resulta que una de sus clases base no tenía un destructor definido (¡el destructor predeterminado está vacío, no es virtual!) Y no se estaba asignando memoria así antes de que no se filtrara memoria hasta ese punto. Muchos días de investigación y tiempo perdido más tarde ...

+1

Así que si entiendo la situación correctamente, tu código ya tenía un comportamiento indefinido (aunque no una fuga de memoria) antes de realizar el cambio: al eliminarse mediante un puntero de clase base, tu objeto derivado se destruye sin que (primero) se destruya . La ausencia de otros miembros de datos (que necesitarían destrucción) no define el comportamiento. Entonces su investigación no fue un esfuerzo desperdiciado ... –

9

Sí, al heredar de una clase base con un destructor virtual. En este caso, ya paga el precio de una clase polimórfica (por ejemplo, vtable).

43

En C++ 11 puede utilizar:

class MyClass 
{ 
    // create a virtual, default destructor 
    virtual ~MyClass() = default; 
}; 
+0

Esto compila con '' icpc'', pero no '' g ++ - 4.6.3'', y le da al mensaje '' error: ~virtual MyClass :: ~ MyClass() declarado virtual no puede ser predeterminado en el cuerpo de la clase''. Parece bastante explícito que no quieren que hagas esto; ¿Hay una versión de '' g ++ '' con la que esto funcione? – user14717

+1

@NickThompson, lo he usado con gcc 4.8.1 y 4.9.0 con éxito. Parece [esto es compatible con 4.6] (https://gcc.gnu.org/gcc-4.6/cxx0x_status.html). ¿Estás compilando con '-std = C++ 0x'? –

+0

Yo estaba; no estoy seguro de lo que estaba pasando allí. – user14717

2

Actualmente, Uri es correcto. Por otro lado, después de que haya declarado un método virtual en su clase, de todos modos está pagando el precio por la existencia de la tabla virtual. De hecho, el compilador le advertirá si su clase tiene un método virtual, pero no un destructor virtual. Esto podría convertirse en un candidato para la generación automática del destructor virtual predeterminado en lugar de la advertencia molesta.

Cuestiones relacionadas