MSVC und unique_ptr



  • Hallo, ich spiele gerade mit ein paar neuen C++-Features rum. MSVC hat rvalue-Referenzen und unique_ptr, aber folgendes funktioniert nicht:

    unique_ptr<int> foo()
    {
      return unique_ptr<int>(new int(42));
    }
    

    Er beschwert sich über einen nicht zugänglichen, da privaten, Kopierkonstruktor. Es sollte doch eigentlich erstmal der Movekonstruktor zum Zuge kommen (und dann sogar ausgelassen werden). Oder versteh ich da was falsch?

    Witzigerweise geht es, wenn man erstmal eine lokale Variable erstellt und die dann zurückgibt. Vielleicht haben die die Überladungsreihenfolge falsch, so dass rvalues sich erstmal an const-lvalue-Referenzen und dann erst an nicht-const-rvalue-Referenzen binden. Wieso finde ich dazu nichts bei Google, wie kann das sein, dass sowas nicht auffällt?

    Man kann foo dann auch nicht vernünftig benutzen:

    void bar()
    {
      unique_ptr<int> ptr(foo());
    }
    

    Selbe Fehlermeldung.

    Und noch eine Standardfrage.

    unique_ptr<int> foo2()
    {
      unique_ptr<int> ptr(new int(42));
      return ptr; // funktioniert mit MSVC
    }
    

    lvalues sollten doch bevorzugt an lvalue-Referenzen gebunden werden (sonst hätte man erstens ein Problem und bräuchte zweitens std::move nicht). Steht irgendwo, dass es da in return -Anweisungen eine Ausnahme gibt, also bei der Überladungsauflösung bevorzugt die rvalue-Referenz genommen wird?



  • Beim zweiten Beispiel erscheint es mir eher so als würde das Return-Statement wegopimiert werden.



  • Ethon schrieb:

    Beim zweiten Beispiel erscheint es mir eher so als würde das Return-Statement wegopimiert werden.

    Das ist Quatsch, der Fehler wäre der gleiche.

    std::unique_ptr<int> foo()
    {
      return std::unique_ptr<int>(new int(5));
    }
    
    int main()
    {
      std::unique_ptr<int> p = foo();
    }
    

    Kompiliert bei mir ohne Murren.



  • Könntet ihr bitte beim Thema bleiben?



  • zum Thema: Das sollte alles kompilieren. Vielleicht ist der Compiler nicht aktuell genug?

    Steht irgendwo, dass es da in return-Anweisungen eine Ausnahme gibt, also bei der Überladungsauflösung bevorzugt die rvalue-Referenz genommen wird?

    Ja, so ähnlich. Wenn das, was du in der return Anweisung benennst und zurückgeben willst, ein Funktions-lokales Objekt ist (inklusive pass-by-value Parameter) dann wird das Ding zunächst wie ein Rvalue behandelt, weil es ja direkt nach dem return zerstört wird und von keinem anderern mehr erreichbar ist. Es verhält sich also prinzipiell wie ein temporäres Objekt. Von daher macht diese Regel schon Sinn. Damit fällt dann auch das std::move weg. Der positive Nebeneffekt: Ohne std::move wird dann auch die NRVO-Optimierung zulässig, so dass die Move-Konstruktion ggf wegoptimiert werden kann.



  • Hm, hab die Version gar nicht genannt 🙄 Es handelt sich um MSVC 10. Der ist nicht ganz bleeding-edge, aber er bringt diese Features immerhin mit, und es wundert mich einfach, dass anscheinend noch keinem aufgefallen ist, dass sie nicht funktionieren.



  • Ja, das ist schon komisch. Ich hätte auch gedacht, dass die 2010er Version aktuell genug sein sollte. Vielleicht doch noch irgendwo ein Anwenderfehler in den Einstellungen? Ich selbst verwende diesen Compiler z.Z. nicht.



  • Also bei mir funktioniert das auch unter MSVC 10 ohne Probleme.

    Du kannst den Fall ja nocheinmal besser beschreiben (inklusive der verwendeten Header und der Fehlermeldungen vom Compiler). Evtl klärt sich der Fall dann auf.



  • Bashar schrieb:

    unique_ptr<int> foo()
    {
      return unique_ptr<int>(new int(42));
    }
    

    Er beschwert sich über einen nicht zugänglichen, da privaten, Kopierkonstruktor.

    Benutzt du die Funktion irgendwo? Welche Standard-Bibliothek? Welche MSVC-Version?



  • Oh, ich habs. "Disable language extensions" war an. Ich hatte die Option eigentlich als "Halte dich an den Standard" interpretiert, also entweder C++98, d.h. rvalue-Referenzen gibts nicht, oder C++11 bzw. 0x, d.h. sie werden korrekt oder zumindest so gut wie möglich unterstützt. Er hat sich da für einen Mittelweg entschieden ...



  • Bashar schrieb:

    entweder C++98, d.h. rvalue-Referenzen gibts nicht, oder [...] Er hat sich da für einen Mittelweg entschieden ...

    Welcher Mittelweg wäre das? Ich würde das als C++98 language ohne die "Teilwweise-C++0x-extension" (und andere extensions) interpretieren.
    IRRC hat MSVC in den Bibliotheken auch überall #ifdefs um die Funktionen, die rrefs und andere C++0x Sprach-Features benutzen. Die Bilbiotheksfeatures sind was anderes - Wie man sieht funktionieren einige neue Teile der Bibliotheken durchaus auch ohne die neuen Sprachfeatures. Dass einige wie std::unique_ptr dann nur sehr eingeschränkt benutzbar sind steht auf einem anderen Blatt 😉



  • pumuckl schrieb:

    Bashar schrieb:

    entweder C++98, d.h. rvalue-Referenzen gibts nicht, oder [...] Er hat sich da für einen Mittelweg entschieden ...

    Welcher Mittelweg wäre das?

    Der Mittelweg zwischen geht nicht und geht ist: geht falsch 🙂

    Ich würde das als C++98 language ohne die "Teilwweise-C++0x-extension" (und andere extensions) interpretieren.

    In C++98 wäre eine rvalue-Referenz ein Syntaxfehler. Ich kann sie aber zunächst ohne Probleme benutzen, meine eigene Klasse mit Movekonstruktor hat auch funktioniert, deshalb bin ich gar nicht auf die Idee gekommen, dass es an dieser Einstellung liegen könnte.



  • Bashar schrieb:

    Könntet ihr bitte beim Thema bleiben?

    Verstehe ich nicht, ich habe doch geschrieben, dass es bei mir so funktioniert. Oder habe ich das Problem nicht verstanden?



  • cooky451 schrieb:

    Verstehe ich nicht, ich habe doch geschrieben, dass es bei mir so funktioniert. Oder habe ich das Problem nicht verstanden?

    Tut mir leid, das war eher an Ethon gerichtet, auf den du geantwortet hast, und ich hatte dein Posting nicht als MSVC-spezifisch erkannt. Dass es irgendwo funktioniert, weiß ich auch, auf dem gcc (ideone) z.B.



  • Bashar schrieb:

    cooky451 schrieb:

    Verstehe ich nicht, ich habe doch geschrieben, dass es bei mir so funktioniert. Oder habe ich das Problem nicht verstanden?

    Tut mir leid, das war eher an Ethon gerichtet, auf den du geantwortet hast, und ich hatte dein Posting nicht als MSVC-spezifisch erkannt. Dass es irgendwo funktioniert, weiß ich auch, auf dem gcc (ideone) z.B.

    Ich dachte dass du meintest dass das zweite Beispiel mit dem MSVC kompiliert aber das erste nicht. Dafür hab ich ne Vermutung abgegeben, mehr nicht. 😉


Anmelden zum Antworten