Die STL Implementierung wurde klar hinsichtlich „perfect forwarding“ überarbeitet (Siehe C++0x). Allerdings sind dabei auch einige Sachen reingerutscht die dazu führen, dass sich mancher Code nicht mehr kompilieren lässt.
So führen die nachfolgenen Zeilen zu einem Compiler Fehler:
std::pair<void*,void*> p(0, NULL); // fails with error C2440: 'initializing' : cannot convert from 'int' to 'void *'
Gleiches negatives Ergebnis erhält man, wenn man die folgenden Zeile kompiliert:
vector<void*> v; v.insert(v.begin(),NULL);
Der Hintergrund wird hier in dieser Connect Meldung beleuchtet:
https://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair?wa=wsignin1.0
Das Problem ist, das 0 (NULL) sich zwar brav in einen Zeiger umwandeln lässt. 0 (NULL) bleibt aber deshalb dennoch vom Typ her ein int ist wird nicht zu einem Zeiger. Die typensichere Implementierung in der STL führt nun dazu, dass 0 (NULL) nicht als void* akzeptiert wird.
Einzige Lösung und auch mein Rat:
Man verwendet nicht mehr 0 oder NULL, wenn ein NULL-Zeiger gemeint ist, sondern nullptr ❗
Wer Code kompatibel zu VC-2008 und früher halten muss, kann ja in seinen Headern den folgende Definition einführen:
#if _MSC_VER<1600 const int nullptr = 0; #endif
Mehr zu perfect forwarding liest man hier:
http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm
http://thbecker.net/articles/rvalue_references/section_07.html
Wie auch aus dem Connect Artikel zu entnehmen ist kann man damit rechnen, dass sich in VC11 alles wieder etwas zurückentwickeln wird. D.h. std::pair und auch die insert Befehle der Container sollen wirde brav 0 aktzeptieren können, wenn Zeiger gemeint sind. Gleiches bekam ich auch über meine Kontakte zur Produktgruppe zu höhren. Aber was VC11 betrifft ist alles sowieso nur Zukunftsmusik und alles noch im dichten Nebel und was wirklich Realität wird muss man dann wohl erst mal sehen 😉
Nachtrag vom 09.09.2010:
Dravere hat in einem Kommentar auf eine geniale Implementierung für nullptr hingewiesen:
http://www.c-plusplus.de/forum/viewtopic-var-t-is-220511.html
Die ist weitaus besser als meine Definition als const int.
const class
{
public:
template<class T> operator T*() const {return 0;}
template<class C, class T> operator T C::*() const {return 0;}
private:
void operator&() const;
}
nullptr = {};
Hallo Martin,
das ist aber kein „define“, was Du da deklarierst… wie ist es denn in VC9 definiert? Als Compiler-Keyword?
Greetings
Jochen
Hi Jochen!
Stimmt! Es ist kein define. In meinem ersten Entwurf des Artikels hatte ich einen #define. Dann habe ich mich für die const Variante entschieden. Ich korrigiere das mal. Danke!
VC9 (auch mit SP1) kennt nullptr gar nicht. Es sind ja auch keine Compiler Erweiterungen aus C++0x reingekommen in SP1/MFCNEXT sondern nur Klassen aus TR1.
Hallo Martin,
Hier noch eine bessere Implementation von nullptr für Versionen vor VS2010 mit den gleichen Eigenschaften:
http://www.c-plusplus.de/forum/viewtopic-var-t-is-220511.html
Grüssli
Stark! Diese nullptr Implementierung gefällt mir, ein sehr guter Beitrag.