nullptr



  • Hallo,
    ich habe mir eben ein Video von Microsoft angeschaut, bei dem der MS-STL-Bibliotheksschreiber in größten Tönen darüber geschwärmt hat, dass man unbedingt die "nullptr"s aus C++0x für "perfect forwarding" braucht. Und dann hat er ein Beispiel an sein Whiteboard gekritzelt, bei dem die Konstruktoren mehrdeutig wurden, durch die Parameterübergabe, was auch absolut nachvollziehbar war. Als Allheillösung musste dann unbedingt Support für nullptrs in den Visual C++-Compiler eingebaut werden. Was ich nicht so ganz verstehe ist, warum das da so als Allheillösung (und ansonsten unlösbar) hingestellt wird, wenn folgendes doch schon wieder zu Problemen führt:

    class a {
    public:
    	a( float* b ) { std::cout << "float ptr!"; }
    	a( double* b ) { std::cout << "double ptr!"; }
    	a( int ) { std::cout << "int!"; }
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	float b;
    	double c;
    	a a1( &b );
    	a a2( &c );
    
    	a a3( (float*)0 );
    	a a4( (double*)0 );
    
    	auto sp1 = std::make_shared<a>( &b );
    	auto sp2 = std::make_shared<a>( &c );
    
    	auto sp3 = std::make_shared<a>( nullptr ); // ????
    
    	return 0;
    }
    

    So wie ich das jetzt im Moment verstehe, ist nullptr (eben weil es keine Typ-angabe zulässt) immernoch nicht die Allheillösung. Warum gibt es denn kein nullptr<typename T>? Und warum haben die sich denn die Mühe gemacht das da extra deswegen reinzubasteln, wenn es doch vorher auch durch explizites type-casting möglich war und hinterher immernoch nicht generell gelöst ist.

    Viele Grüße,
    Michael



  • Decimad schrieb:

    Was ich nicht so ganz verstehe ist, warum das da so als Allheillösung (und ansonsten unlösbar) hingestellt wird, wenn folgendes doch schon wieder zu Problemen führt:

    class a {
    public:
    	a( float* b ) { std::cout << "float ptr!"; }
    	a( double* b ) { std::cout << "double ptr!"; }
    	a( int ) { std::cout << "int!"; }
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	float b;
    	double c;
    	a a1( &b );
    	a a2( &c );
    
    	a a3( (float*)0 );
    	a a4( (double*)0 );
    
    	auto sp1 = std::make_shared<a>( &b );
    	auto sp2 = std::make_shared<a>( &c );
    
    	auto sp3 = std::make_shared<a>( nullptr ); // ????
    	
    	return 0;
    }
    

    So wie ich das jetzt im Moment verstehe, ist nullptr (eben weil es keine Typ-angabe zulässt) immernoch nicht die Allheillösung.

    Du vermischt hier zwei Dinge. Das Problem hat nichts mit Perfect Forwarding zu tun; denn

    a a5( nullptr );
    

    funktioniert ja auch schon nicht.

    Decimad schrieb:

    Warum gibt es denn kein nullptr<typename T>?

    Wäre es denn so praktisch? Ich bin da gar nicht von überzeugt. Im Notfall schreibst Du eben static_cast<float*>(0). Das ist auch nicht viel länger. Aber ich gehe nicht davon aus, dass man so etwas oft bräuchte.

    Decimad schrieb:

    Und warum haben die sich denn die Mühe gemacht das da extra deswegen reinzubasteln, wenn es doch vorher auch durch explizites type-casting möglich war und hinterher immernoch nicht generell gelöst ist.

    nullptr wird auch als nullptr "geforwardet". Alles paletti, sozusagen. Das Problem ist doch, dass 0 ein Doppelleben führt. Es ist eine Nullzeiger-Konstante und eine Int-Konstante, wobei Template-Argument-Deduction 0 einfach als int behandelt und damit der Status von 0 als Nullzeigerkonstante verloren geht.

    template<class T>
    void foo(T x);
    
    void bar() {
      foo(0);       // T=int, x ist keine Nullzeigerkonstante mehr :-(
      foo(nullptr); // T=nullptr_t, x ist immernoch ein Nullzeiger :-)
    }
    

    kk



  • Ja, ich sehe ja ein, dass der nullptr halt eine Typ-Eigenschaft mit in die Template-Argumente reinschleift, die man für eine '0'-konstante dort nicht hätte.
    Aber warum macht man dann genau bei der Pointer-Eigenschaft halt? Cool wäre gewesen, wenn man nullptr verwenden kann wenn das halt statt falscher Template-Auflösung doppeldeutig wird noch nullptr<int>. Wäre doch ziemlich übersichtlich!

    Aber zurück zurück zu meinem Eingangsposting. Ich sehe jetzt ein, dass in meinem Beispiel statt stillschweigend die eventuell falsche Überladung zu benutzen immerhin ein Fehler mit doppeldeutigkeit ausgegeben wird, wenn man nullptr einsetzt. Wobei man halt erst noch dazu übergehen muss, diese wirklich einzusetzen (man hätte ja auch schon immer typ*(0) schreiben können) und sie dann im Falle von doppeldeutigkeiten trotzdem nicht direkt einsetzen kann. Ich find das irgendwie nicht der Weisheit letzter Schluss...^^

    Edit: Und die Argumentation des MS-Typen war halt wirklich, dass sie wegen des Perfect Forwarding nullptr einbauen mussten (aus genannten Gründen), was sie eigentlich gar nicht für vc++10 vorhatten.



  • Decimad schrieb:

    Aber warum macht man dann genau bei der Pointer-Eigenschaft halt?

    ...weil's für 99% aller Fälle ausreicht und weil es auch noch static_cast<XYZ*>(0) gibt, falls man einen spezielleren Zeigertypen braucht.



  • @krümelkracker: nullptr_t? Ist das die Neuerfindung von void*?



  • Habe mich verlesen.



  • wxSkip schrieb:

    @krümelkracker: nullptr_t? Ist das die Neuerfindung von void*?

    Nein. nullptr ist Literal vom Typ std::nullptr_t so wie true und false Literale vom Typ bool sind. std::nullptr_t wird in irgend einem Standard-Header als decltype(nullptr) definiert. Es handelt sich hier um einen neuen Typen. Und das einzige, was dieser Typ kann, ist, implizite Konvertierungen zu jedem Zeigertyp anzubieten. Das Ergebnis einer solchen Konvertierung ist dann ein Nullzeigerwert des entsprechenden Zieltyps.



  • Das heißt, man kann dann aber nicht jeden x-beliebigen Wert in diesen Pointer reinschreiben, sondern nur 0?



  • Welchen "Pointer" meinst Du?



  • wxSkip schrieb:

    Das heißt, man kann dann aber nicht jeden x-beliebigen Wert in diesen Pointer reinschreiben, sondern nur 0?

    std::nullptr_t ist kein Zeigertyp. Es ist der Typ der Nullzeigerkonstante nullptr. Also nein, Du kannst nullptr_t nicht wie void* benutzen. Und umgekehrt auch nicht.


Anmelden zum Antworten