optionale const reference auf nullptr setzen funktioniert, aber warum?
-
Habe gerade versucht im Titel genanntes zu machen:
void nullPointerReference(const SomeClass& foo = nullptr) { //... }
und war überrascht das es ging!
Dann nachgeforscht und festgestellt, dass ich in SomeClass KEINEN Constructor für std::nullptr_t habe:
//Ist nicht im Code SomeClass::SomeClass(std::nullptr_t nullPointer) { //... }
habe.
Kompiliert ohne Warnung und Fehler
Hab dann gefunden was passiert ist!Wisst ihr auch was es war? Und ist das so gewollt?
-
Deine Dummheit? Keine Ahnung.
-
Da ist der Wurm drin. Was passiert wenn man
int main() { nullPointerReference() }
aufruft?
Da der Constructor
SomeClass(std::nullptr_t nullPointer)
nicht existiert, wird wohl ein andere Constructor aufgerufen, aber welcher könnte denn da passen?
Nun ein Constructor der einen Pointer eines beliebigen typs akzeptiert könnte passen z.B.:
SomeClass(int* pInt); SomeClass(AnohterClass* anotherPointer); //usw...
Aber auch keiner dieser Signaturen befindet sich in SomeClass!
-
nullptr lässt sich in beliebige Zeiger (auf Objekte oder Funktionen) oder in Zeiger auf Member oder in Zeiger auf Memberfunktionen oder auch in bool konvertieren. Dein gesuchter Konstruktor wird wohl entweder nullptr_t selbst oder eben eines dieser Konvertierungsergebnisse akzeptieren.
P.S. Für Ich-sehe-was-was-du-nicht-siehst-Spiele gibt es bessere Foren.
-
camper schrieb:
nullptr lässt sich [...] auch in bool konvertieren. [...]
Das ist passiert und ich fand das nicht gerade intuitiv.
-
Ufftata schrieb:
camper schrieb:
nullptr lässt sich [...] auch in bool konvertieren. [...]
Das ist passiert und ich fand das nicht gerade intuitiv.
Dann viel Spaß, wenn du demnächst überall
if(pointer != nullptr)
schreibst, anstattif(pointer)
.
-
SeppJ schrieb:
Ufftata schrieb:
camper schrieb:
nullptr lässt sich [...] auch in bool konvertieren. [...]
Das ist passiert und ich fand das nicht gerade intuitiv.
Dann viel Spaß, wenn du demnächst überall
if(pointer != nullptr)
schreibst, anstattif(pointer)
.nullptr_t != T*
-
SeppJ schrieb:
Dann viel Spaß, wenn du demnächst überall
if(pointer != nullptr)
schreibst, anstattif(pointer)
.Huch?
if (pointer)
wäre doch bloss ein Problem wenntypeof(pointer) == nullptr_t
. Also vermutlich nur innerhalb von Templates, wieso sonst sollte man ne Variable vom Typnullptr_t
machen und dann explizit gucken ob sie denn null ist?
Also schon nervig aber nicht MEGA-nervig.Und davon abgesehen, um es zu erlauben hätte auch ein expliziter
operator bool
gereicht (if (expression)
gilt ja als explizite Konvertierung nach bool).Bin also auch etwas überrascht dass hier implizit konvertiert wird.
Oder steh ich grav vollkommen auf dem Schlauf
-
Was SeppJ wohl meinte: "Die Konvertierung von
nullptr
nachbool
funktioniert weilnullptr
in einen Zeiger konvertiert werden kann [das ist falsch, denn dann wäre die Konvertierung mehrdeutig], und die konvertieren nachbool
. Wenn letzteres verboten wird, dann funktioniertif (ptr)
nicht mehr."
-
hustbaer schrieb:
Und davon abgesehen, um es zu erlauben hätte auch ein expliziter
operator bool
gereicht (if (expression)
gilt ja als explizite Konvertierung nach bool).Bin also auch etwas überrascht dass hier implizit konvertiert wird.
Ich nicht. Warum sollten sich null pointer values und pointer unterschiedlich benehmen, wenn ich sie einem
bool
zuweise? Gerade das wäre verwirrend.
-
C++14 präzisiert, dass die Konvertierung nur im Kontext einer Direktinitialisierung zulässig ist (wobei die genaue Bedeutung dieser Regel auch nicht völlig glasklar zu sein scheint #1781).
Kurzer Test mit g++ (5.4.0,6.3.0,7.1.0): verweigert die Konvertierung für -std=c++11 und -std=c++14 und -std=c++17
clang 4.0.0: führt die Konvertierung durch für alle Versionen, warnt aber auch in allen Fällen.
-
Hmm. Im Nachhinein macht es doch Sinn. Schließlich war einer der motivierenden Gründe overload resolution:
void f(bool); void f(int*); f(nullptr); // call #2
Implizite Konvertierung nach
bool
würde zumindest dieses Beispiel brechen.
-
Arcoth schrieb:
Hmm. Im Nachhinein macht es doch Sinn. Schließlich war einer der motivierenden Gründe overload resolution:
void f(int); void f(int*); f(nullptr); // call #2
Implizite Konvertierung nach
bool
würde alle arithmetischen Typen mit sich ziehen. In diesem Beispiel wäre das egal, weil die zweite SCS in der UCS für #1 schlechter wäre (Promotion statt Identität). Aber es wäre trotzdem nicht gewollt, dassnullptr
das Verhalten aufweist.Eine Standardkonvertierungssequenz kann nur maximal eine "richtige" Konvertierung haben (der Kram, der gleich am Anfang des Kapitels (jetzt 7 Standard Conversions) steht).
nullptr_t->bool->int geht nicht in einer einzigen Sequenz.
-
Ja, ich hatte zu pragmatisch gedacht;
nullptr_t
ist keine Klasse. Allerdings hast du den Edit verpasst. :p
-
Wenn mich mein Geächtnis nicht täuscht, war u.a. auch genau dieses Beispiel eines, um motivierend zu zeigen, warum nullptr_t als Klasse nicht funktioniert (um NULL zu ersetzen), und direkte Unterstützung durch den Sprachkern erforderlich ist. Wer Lust hat, kann sich ja das entsprechende Paper zu Gemüte führen, ist ja nur ein paar Klicks entfernt.
-
camper schrieb:
Wenn mich mein Geächtnis nicht täuscht, war u.a. auch genau dieses Beispiel eines, um motivierend zu zeigen, warum nullptr_t als Klasse nicht funktioniert (um NULL zu ersetzen), und direkte Unterstützung durch den Sprachkern erforderlich ist.
Weil explizite Konvertierungsoperatoren nicht standardisiert waren? Oder weil ein Konvertierungsoperator-Template in overload resolution einem non-template Konverierungsoperator per se unterliegt? Ich frage mich, ob man letzteres durch ein Template mit default argument lösen könnte.
-
Arcoth schrieb:
camper schrieb:
Wenn mich mein Geächtnis nicht täuscht, war u.a. auch genau dieses Beispiel eines, um motivierend zu zeigen, warum nullptr_t als Klasse nicht funktioniert (um NULL zu ersetzen), und direkte Unterstützung durch den Sprachkern erforderlich ist.
Weil explizite Konvertierungsoperatoren nicht standardisiert waren? Oder weil ein Konvertierungsoperator-Template in overload resolution einem non-template Konverierungsoperator per se unterliegt? Ich frage mich, ob man letzteres durch ein Template mit default argument lösen könnte.
u.a. Das Problem mit NULL wurde ja schon diskutiert, bevor C++ überhaupt standardisiert wurde.
Nachdem ich nochmal die entsprechenden Teile rausgesucht habe (N2431 #654 N2656), muss ich feststellen, dass ich mich wahrscheinlich getäuscht habe. Eventuell habe ich das mit einer Diskussion über bool-Konvertierungen für Smartpointer verwechselt (bevor es explizite Konvertierungsoperatoren gab) - da war es so dass dieser unspecified-bool am Besten (die beste Variante von mehreren schlechten Lösungen, wohlgemerkt) ein Zeiger auf Member(funktion) ist, damit nicht so komische Sachen wie:smart_ptr p; p*42;
möglich sind.
-
SeppJ schrieb:
Dann viel Spaß, wenn du demnächst überall
if(pointer != nullptr)
schreibst, anstattif(pointer)
.Auch wenn das nicht deine Welt ist: Bin kein Freund von impliziten Typumwandlungen und schreibe so etwas tatsächlich meist explizit aus - obwohl mir
die impliziten Umwandlungen bekannt sind und ich weiss dass es nicht nötig wäre. Vorteil: Im Zweifelsfall lässt sich direkt aus dem Code ablesen, dass die
Umwandlung so gewollt war und sich jemand Gedanken darüber gemacht hat. Weniger schreiben zu müssen empfand ich beim Programmieren noch nie als
großen Vorteil, da zumindest bei mir die meiste Zeit nicht fürs Tippen draufgeht