2012-12-15 4 views
6

Ricevo un errore del linker nel mio codice. L'ho individuato nel minimo essenziale di seguito.Errore di linker "vtable" (che coinvolge un distruttore virtuale con "= default") - potenziale bug in Clang 3.1?

Questo codice dà l'errore di linker "vtable per Pippo", si fa riferimento da: Pippo :: Foo()

class Foo { 
public: 
    Foo(); 
    virtual ~Foo() = default; 
}; 
Foo::Foo() { } 

Ma questo codice non dà errori:

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

Perché? Pensavo che lo = default avrebbe dovuto sostanzialmente fare la stessa cosa di quelle parentesi quadre vuote.

Aggiornamento: Sto utilizzando il "compilatore Apple LLVM 4.1", una parte di Xcode 4.5.2. Potrebbe essere un bug in questo compilatore? Potrebbe funzionare anche sull'ultimo GCC (che però la Apple non spedisce più). Vedi i commenti sotto per una discussione sui compilatori.

Aggiornamento 2: Come illustrato di seguito, la modifica della riga su virtual inline ~Foo() = default; elimina questo errore. Questo non è semplicemente il essere un bug? Sembra che il compilatore non riconosca una funzione inline in questo caso senza scrivere esplicitamente inline.

+0

Provare 'virtual ~ Foo() noexcept = default;'. Penso di aver avuto un problema simile una volta e ho rinunciato a "default". Inoltre, penso che ci sia anche una DR su questo. –

+0

@KerrekSB L'errore del linker è ancora presente con 'noexcept'. –

+0

Questo funziona per me con gcc 4.7.2. – Kocka

risposta

1

Funziona per me con g ++ 4.7.2. Ma ho lo stesso problema con te con clang 3.1.

Ho 3 file.

foo.h:

#ifndef FOO_H 
#define FOO_H 

class Foo { 
public: 
    Foo(); 
    virtual ~Foo() = default; 
}; 

#endif // FOO_H 

Foo.cpp:

#include "Foo.h" 

Foo::Foo() { } 

main.cpp:

#include <iostream> 
#include "Foo.h" 

using namespace std; 

int main() 
{ 
    Foo foo; 
    return 0; 
} 

Ma se è così, che funziona con clangore così :

Foo.cpp è vuoto.

main.cpp

#include <iostream> 
#include "Foo.h" 

using namespace std; 

Foo::Foo() { } 

int main() 
{ 
    Foo foo; 
    return 0; 
} 

Quindi credo che clang ha bug durante la generazione del objectfile.

2

Nell'ABI Itanium, la v-table (e altre informazioni RTTI) viene emessa per l'unità di traduzione che contiene la definizione del primo metodo virtuale non definito in linea nella classe, o se ci sono solo metodi virtuali definiti in linea, per ogni unità di traduzione che include la classe. Spetta quindi al linker unire i simboli ridondanti.

E 'possibile che specificando = default, Clang non rendersi conto che avete definito il virtual metodo di linea in classe e che ogni TU che include il file necessario definire il v-table e informazioni RTTI, e invece è in attesa che la definizione appaia da qualche parte.

Posso suggerire di inserire la definizione all'esterno della classe? =>Foo::~Foo() = default;

+0

Ha davvero funzionato per mettere 'Foo :: ~ Foo() = defa ult; 'nel file di implementazione (ad es. non il file di intestazione in cui è la definizione della classe). Tuttavia, interessante, ha anche lavorato per aggiungere "in linea" alla linea all'interno della classe stessa: 'virtuale inline ~ Foo() = default;' Non è un bug garantito? Sembra che non riconosca la linea, anche se è in linea. –

+0

@DennisRitchie: Sembra sicuramente un bug. Non sono sorpreso dato che '= default' è un nuovo costrutto. Come tutte le novità, ci vuole tempo per scovare i bug. –

+0

Ho appena scoperto che l'errore del linker scompare se esiste semplicemente una sottoclasse che deriva da 'Foo' (anche se la sottoclasse è vuota). Avete spiegazioni tecniche sul perché questo renderebbe il compilatore più felice? –

3

It appears to be a bug in clang which has been fixed already. Hai chiesto in un momento opportuno, in quanto una nuova versione dovrebbe essere disponibile a breve: release candidates are already available. Per favore provali, il tuo esempio funziona nella versione binaria i386-linux e dovrebbe funzionare in tutti loro.

+0

Oh, dolce! Aspetterò solo che il vero Clang 3.2 appaia su Xcode. Ci vorranno mesi probabilmente. Fino a quel momento terrò quello "in linea" in più. –

+1

Buon lavoro a scoprirlo! Mi piace il modo in cui la correzione è composta da due righe di codice;) –