2015-07-28 11 views
12

In un contesto indipendente (senza librerie standard, ad esempio in fase di sviluppo del sistema operativo) usando g ++ il seguente fenomeno si verifica:Perché operatore delete richiesto per distruttori virtuali

class Base { 
public: 
    virtual ~Base() {} 
}; 

class Derived : public Base { 
public: 
    ~Derived() {} 
}; 

int main() { 
    Derived d; 
} 

Quando si collega afferma qualcosa di simile: undefined reference to operator delete(void*)

Ciò significa chiaramente che g ++ sta generando chiamate per eliminare l'operatore anche se non ci sono allocazioni di memoria dinamica zero. Questo non succede se il distruttore non è virtuale.

Sospetto che questo abbia a che fare con il vtable generato per la classe, ma non ne sono del tutto sicuro. Perché succede?

Se non è necessario dichiarare un operatore di cancellazione a causa della mancanza di routine di allocazione dinamica della memoria, c'è un problema?

Edit1:

di riprodurre con successo il problema in g ++ 5.1 che ho usato:

g ++ -ffreestanding -nostdlib foo.cpp

+0

Non riesco a riprodurre il problema per questo semplice esempio. Sei sicuro di non mancare qualcosa? –

+0

@RobinKrahl hai provato ad aggiungere -ffreestanding alla riga di comando g ++. Controllare il dump dello smontaggio se ci sono delle chiamate per eliminare l'operatore. – felknight

+0

Compila usando g ++ 4.8.4 sul mio Linux Mint. Usato 'g ++ Testing.cpp -ffreestanding'. Ma con clang 3.5.0 ho un sacco di errori di linker. – ChajusSaib

risposta

13

A causa di distruttori eliminazione. Quelle sono le funzioni effettivamente chiamate quando si chiama delete obj su un oggetto con distruttori virtuali. Chiama il distruttore completo dell'oggetto (che gestisce i distruttori di oggetti di base, quelli che si definiscono effettivamente) e quindi chiama operator delete. In tal modo, in tutti i punti in cui viene utilizzato lo delete obj, è necessario emettere una sola chiamata e anche chiamare lo operator delete con lo stesso puntatore restituito da operator new come richiesto da ISO C++ (sebbene ciò potrebbe essere reso più costoso tramite dynamic_cast).

Fa parte del Itanium ABI utilizzato da GCC.

Non penso che si possa disabilitare questo.

+0

Grazie per la risposta. D'accordo con @Yakk. Ora capisco cosa succede. Pensi che ci sia una soluzione alternativa – felknight

+0

@Felipe dal momento che l'eliminazione del distruttore verrà chiamata solo da un 'delete', e dal momento che non ne hai uno, potresti implementare il tuo' delete (void *) 'e non fare nulla o genera un errore di runtime. –

+0

@MarkRansmo Stai dicendo che non c'è possibilità che venga chiamato da una normale distruzione di una classe derivata? – felknight