2011-06-15 15 views
5

Desde el estándar de C++ (ISO/IEC 14882: 2003 (E)), §12.5.4, sobre la sobrecarga operator delete:sobrecarga de operadores borrar en una clase base

Si una eliminación expresión comienza con un unario :: operador, el nombre de la función de desasignación se busca en el alcance global. De lo contrario, si delete-expression se usa para desasignar un objeto de clase cuyo tipo estático tiene un destructor virtual, la función de desasignación es la que encuentra la búsqueda en la definición del destructor virtual del tipo dinámico (12.4). De lo contrario, si delete-expression se usa para desasignar un objeto de clase T o una matriz de los mismos, los tipos estáticos y dinámicos del objeto serán idénticos y el nombre de la función de desasignación se buscará en el alcance de T. Si esta búsqueda falla para encontrar el nombre, el nombre se busca en el alcance global. Si el resultado de la búsqueda es ambiguo o inaccesible, o si la búsqueda selecciona una función de desasignación de ubicación, el programa está mal formado.

§12.5.7 también es interesante:

Dado que las funciones de asignación y desasignación miembro son estáticos no pueden ser virtuales. [Nota: sin embargo, cuando la expresión de conversión de una expresión de eliminación se refiere a un objeto de tipo de clase, porque la función de desasignación realmente llamada se busca en el alcance de la clase que es el tipo dinámico del objeto, si el destructor es virtual, el efecto es el mismo. Por ejemplo,

struct B { 
    virtual ˜B(); 
    void operator delete(void*, size_t); 
}; 
struct D : B { 
    void operator delete(void*); 
}; 
void f() 
{ 
    B* bp = new D; 
    delete bp; // uses D::operator delete(void*) 
} 

Aquí, el almacenamiento para el objeto no es de array de clase D se desasigna por D :: operador delete(), debido a la destructor virtual.]

Después de leer esto, me pregunto ...

  • ¿Es esta parte del estándar totalmente compatible con todos los principales compiladores de C++ (MSVC++, GCC)?
  • Si es así, ¿cómo lo hicieron? ¿Funcion virtual oculta? Llamada de destructor virtual "especial" RTTI?
  • Usando el ejemplo del estándar: ¿puede haber problemas si f() y D :: operator delete() se definen en EXE/DLL/DSO por separado? (Suponiendo que todo está compilado usando el mismo compilador, por supuesto)

§5.3.5.5 también pueden ser relevantes:

En la primera alternativa (eliminar objeto), si el tipo estático de la operand es diferente de su tipo dinámico, el tipo estático debe ser una clase base del tipo dinámico del operando y el tipo estático debe tener un destructor virtual o el comportamiento no está definido. En la segunda alternativa (eliminar matriz) si el tipo dinámico del objeto a eliminar difiere de su tipo estático, el comportamiento no está definido.

+0

Supongo que caminan en la mesa virtual. Como dice el estándar, la clase necesita tener un destructor virtual para funcionar de la manera correcta. Esto también es cierto para la versión no sobrecargada de 'delete'. – Xeo

+0

Intenté responder, pero parece que lo que realmente desea es que alguien investigue el código fuente de GCC y le informe. Creo que puedes hacerlo tú mismo. – littleadv

Respuesta

6

No sé mucho sobre VC++ ABI, pero el Itanium ABI está bien documentado.

Mirando hacia arriba en the name mangling scheme, uno ver:

<ctor-dtor-name> ::= C1  # complete object constructor 
       ::= C2  # base object constructor 
       ::= C3  # complete object allocating constructor 
       ::= D0  # deleting destructor 
       ::= D1  # complete object destructor 
       ::= D2  # base object destructor 

De interés: D0 # deleting destructor, lo que significa que a pesar de que delete es no virtual, ya que se llama desde el destructor virtual, se puede considerar virtual para todos efectos y propósitos

+0

Eso es interesante, gracias. Marcaré su respuesta como aceptada, al menos hasta que alguien presente una respuesta más específica para x86. –

+1

@ e-t172: No creo que necesite una respuesta específica 'x86' (procesador). Esta es una decisión de alto nivel, y aunque se ve en el ABI, dudo seriamente de que VC++, gcc o clang implementen soluciones de problemas específicas en los back-end para esto. –

0

Después de cavar en el código de montaje en emiten por GCC 4.8

El GCC generará dos piezas de código (por clase cuyos destructor es virtual):

One is assembly snippet#1 for {Destructor + Dealloc} 
The other is assembly snippet#2 for {Destructor only} 

y para la clase cuyo destructor es no virtual, la instrucción de función de desasignación de llamada se generará en el punto donde se llama eliminar.

(Después de asumir la discusión el destructor es virtual) Así que para siguiente código:

delete C // This will be translate as call snippet#1 for the correct dynamic type 

Y si el código es el siguiente:

p->C::~C() // this will be translate to call snippet#2 

Por lo tanto la función deallocate se unen junto con el Virtual incinerador de basuras. Así que creo que esto responderá a su pregunta sobre cómo implementar la función de desasignar como virtual, pero también estática.

Cuestiones relacionadas