2012-12-15 11 views
6

Otrzymuję błąd linkera w moim kodzie. Zauważyłem to do podstawowych rzeczy poniżej.Błąd łącznika "vtable" (z udziałem destruktora wirtualnego z "= default") - potencjalny błąd w Clang 3.1?

Ten kod daje błąd linkera "vtable dla Foo", odwołuje się od: Foo :: Foo()

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

ale ten kod nie daje żadnych błędów:

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

Dlaczego? Myślałem, że = default miał w zasadzie zrobić to samo, co puste nawiasy kwadratowe.

Aktualizacja: Używam "Kompilatora Apple LLVM 4.1", część Xcode 4.5.2. Czy może to być błąd w tym kompilatorze? Być może działa na najnowszym GCC (którego Apple już nie wysyła). Zobacz poniżej komentarze do dyskusji na temat kompilatorów.

Aktualizacja 2: Jak omówiono poniżej, zmiana linii na virtual inline ~Foo() = default; usuwa ten błąd. Czy to po prostu ma jako błąd? Wygląda na to, że kompilator nie rozpoznaje funkcji wstawiania w tym przypadku bez jawnego napisania inline.

+0

Wypróbuj 'virtual ~ Foo() noexcept = default;'. Myślę, że kiedyś miałem podobny problem i zrezygnowałem z "domyślnego". Co więcej, myślę, że w tym jest nawet DR. –

+0

Błąd @KerrekSB Linker nadal występuje z 'noexcept'. –

+0

Działa to dla mnie z gcc 4.7.2. – Kocka

Odpowiedz

1

Działa dla mnie z g ++ 4.7.2. Ale mam ten sam problem co ty z clang 3.1.

Mam 3 pliki.

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; 
} 

Ale jeśli tak jest, to działa z brzękiem, jak również :

Foo.cpp jest pusty.

main.cpp

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

using namespace std; 

Foo::Foo() { } 

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

Więc myślę, dzyń ma błąd podczas generowania objectfile.

2

W ABI Itanium, tablica v (i inne informacje RTTI) są emitowane dla jednostki tłumaczeniowej zawierającej definicję pierwszej wirtualnej metody nieokreślonej w linii w klasie, lub jeśli istnieją tylko metody wirtualne zdefiniowane w linii, dla każdej jednostki tłumaczeniowej, która obejmuje klasę. To zależy od łącznika, aby scalić nadmiarowe symbole.

Jest możliwe, że przez określenie = default, Clang nie zdaje sobie sprawy, że masz zdefiniowany inline virtual metoda w klasie i że każdy TU, który zawiera plik powinien zdefiniować v-table i informacje RTTI i zamiast tego czeka, aż definicja pojawi się gdzieś.

Czy mogę zaproponować umieszczenie definicji na zewnątrz klasy? =>Foo::~Foo() = default;

+0

Rzeczywiście, działało to na 'Foo :: ~ Foo() = defa ult; 'do pliku implementacji (tj. nie plik nagłówkowy, w którym znajduje się definicja klasy). Co ciekawe, działało również na dodanie 'inline' do linii w samej klasie:' virtual inline ~ Foo() = default; 'Czy to nie jest gwarantowany błąd? Wygląda na to, że nie rozpoznaje linii, nawet jeśli jest wbudowany. –

+0

@DennisRitchie: Z pewnością brzmi jak błąd. Nie jestem zaskoczony, ponieważ '= default' jest nową konstrukcją. Jak wszystkie nowe rzeczy, potrzeba czasu, aby wyplenić błędy. –

+0

Właśnie się dowiedziałem, że błąd linkera znika, jeśli istnieje po prostu podklasa wywodząca się z 'Foo' (nawet jeśli podklasa jest pusta). Czy masz jakieś techniczne wyjaśnienia, dlaczego kompilator byłby szczęśliwszy? –

3

It appears to be a bug in clang which has been fixed already. Zapytałeś w odpowiednim czasie, ponieważ wkrótce powinno pojawić się nowe wydanie: release candidates are already available. Wypróbuj je, twój przykład działa w wersji binarnej i386-linux i powinien działać we wszystkich z nich.

+0

O, słodko! Po prostu poczekam na pojawienie się prawdziwego Clanga 3.2 w Xcode. Prawdopodobnie potrwa miesiące. Do tego czasu utrzymam tam dodatkowy "inline". –

+1

Dobra robota, znajdując to! Podoba mi się, jak poprawka składa się z dwóch linii kodu;) –

Powiązane problemy