Der ganze Fehler lässt sich mit folgendem Testfall reproduzieren:
//TestLib.hpp
class Base {
public:
virtual ~Base() {}
};
template <typename T>
class Derived : public Base {
public:
Derived();
};
/*TestLib.cpp
* compile with: g++ -dynamiclib TestLib.cpp -o libTestLib.dylib
*/
#include "TestLib.hpp"
#include <typeinfo>
#include <iostream>
template <typename T>
Derived<T>::Derived() {
std::cout << typeid(*this).name() << std::endl;
}
template class Derived<int>;
Wie man in der letzten Zeile sieht wird das Template
Derived
explizit mit int
in TestLib.cpp instanziiert. Diesen Typen werden wir jetzt in einer kleinen Anwendung etwas durch die Typhierarchie scheuchen und ein sehr seltsames Verhalten beobachten.
/* main.cpp
* compile with: g++ -L. -lTestLib main.cpp -o main
*/
#include "TestLib.hpp"
#include <iostream>
int main() {
Derived<int>* i = new Derived<int>();
std::cout << typeid(*i).name() << std::endl;
Base *o = i;
std::cout << typeid(*o).name() << std::endl;
std::cout << o << std::endl;
std::cout << dynamic_cast< Derived<int>* >(o) << std::endl;
std::cout << typeid(*o).name() << std::endl;
delete i;
}
Wir erhalten folgende Ausgabe:
7DerivedIiE
7DerivedIiE
0x100100080
0
7DerivedIiE
Die Typid verändert sich nicht und trotzdem liefert ein gültiger Downcast den Nullpointer zurück. Ich habe den Code ebenfalls unter FreeBSD und DragonflyBSD getestet, in beiden Fällen war der Downcast erfolgreich. Meines Wissens tritt dieses Verhalten erst seit Snow Leopard auf, aber da ich derzeit nirgends eine aktuelle Version von Leopard laufen habe kann ich nicht testen ob es sich hier um einen neuen Bug handelt.
Der einzige Workaround der mir derzeit einfällt ist die Instanziierung des Templates in die Compilezeit der Anwendung zu verlegen.
UPDATE: Mal ein delete nachgebessert, nicht das sich hier noch jemand beschwert das mein Testcase leakt :P