unique_ptr Funktionsargument



  • void f(std::unique_ptr<int> u);
    

    Geht das überhaupt? Ich dachte man kann von einem unique_ptr keine Kopie machen.



  • TNA schrieb:

    void f(std::unique_ptr<int> u);
    

    Geht das überhaupt? Ich dachte man kann von einem unique_ptr keine Kopie machen.

    Exakt meine Frage auf der ersten Seite, auch dort beantwortet.



  • Deshalb frage ich, aber ich habe nicht gesehen das jemand direkt darauf geantwortet hätte oder ich verstehe zumindest die Antwort nicht.



  • void f(std::unique_ptr<int>&& u)
    

    Eine RValue-Referenz als Funktionsparameter mache ich doch wenn ich Ownership übertragen möchte oder? Also der Aufrufer weiß an der Stelle, dass er das übergebene Objekt nicht weiter benutzen kann oder darf oder?



  • TNA schrieb:

    Eine RValue-Referenz als Funktionsparameter mache ich doch wenn ich Ownership übertragen möchte oder?

    Nein, sondern wenn nur RValues als Argumente akzeptiert werden sollen. Typischerweise sind das temporäre Objekte oder Rückgabewerte von std::move() . Am ehesten brauchst du RValue-Referenz-Parameter bei Move-Konstruktor und Move-Zuweisungsoperator (oder wenn du spezifisch optimieren willst, um Moves zu vermeiden). Ansonsten würde ich Pass By Value grundsätzlich vorziehen, da es flexibler ist und in vielen Fällen Codeduplizierung (Überladung für T&& und const T& ) vermeidet.

    Wichtig ist zu sehen, dass RValue-Referenz und Move-Semantik verschiedene Konzepte sind. Zwar hängen sie insofern zusammen, als Move-Semantik auf Klassenebene über RValue-Referenzen implementiert wird; doch viele Moves geschehen, ohne dass ein && in der Funktion oder im Aufruf auftritt.

    Die Signatur

    void f(std::unique_ptr<int> u);
    

    drückt bereits aus, dass hier Besitz zur Funktion übertragen wird -- einfach durch die Semantik von unique_ptr , der nur gemoved werden kann. Pass By Value impliziert hier also Besitzübertragung. Diese Signatur verwirrt wahrscheinlich auch weniger.



  • @otze: Das meintest du! In Ordnung, tut mir Leid. Ja, ich habe falsche Annahmen über die Anforderungen gestellt. Tatsächlich sollte ich solche Pauschalaussagen einfach unterlassen. 🙂

    oder wenn du spezifisch optimieren willst, um Moves zu vermeiden

    *Kopien

    Hier wird auch die Falschheit meiner Aussage deutlich. Hätte man einen shared_ptr verwendet, so könnte man bspw. auch einen anderen shared_ptr übergeben - es kann aber nie davon ausgegangen werden, dass der Ownership ganz an die Funktion übergeht. Bei unique_ptr ist das, wie Nexus erklärt hat, impliziert.



  • Sone schrieb:

    oder wenn du spezifisch optimieren willst, um Moves zu vermeiden

    *Kopien

    Nein, ich meinte schon Moves.

    Mit RValue-Referenzen hast du bereits eine Referenz auf das Originalobjekt, daher ist der Move unnötig.



  • Nexus schrieb:

    Sone schrieb:

    oder wenn du spezifisch optimieren willst, um Moves zu vermeiden

    *Kopien

    Nein, ich meinte schon Moves.

    Mit RValue-Referenzen hast du bereits eine Referenz auf das Originalobjekt, daher ist der Move unnötig.

    Ach, du meinst mit Move statt dem Cast zu einer rvalue-Referenz durch std::move den Aufruf eines Move-Konstruktors. Klar, der kann natürlich auch Overhead verursachen. 💡



  • Nexus schrieb:

    Die Signatur

    void f(std::unique_ptr<int> u);
    

    drückt bereits aus, dass hier Besitz zur Funktion übertragen wird -- einfach durch die Semantik von unique_ptr , der nur gemoved werden kann. Pass By Value impliziert hier also Besitzübertragung. Diese Signatur verwirrt wahrscheinlich auch weniger.

    Gerade diese Signatur verwirrt mich extrem. Es war doch genau die Frage, wie man ein Objekt per Value über geben kann, dass nicht kopiert werden kann. Was für einen Sinn macht das?



  • TNA schrieb:

    Es war doch genau die Frage, wie man ein Objekt per Value über geben kann, dass nicht kopiert werden kann. Was für einen Sinn macht das?

    Das Verständnis "Pass By Value == Kopie" ist veraltet.

    In C++11 kann Pass By Value den Aufruf eines Move-Konstruktors statt eines Kopierkonstruktors bedeuten. Daher macht es sehr wohl Sinn, nichtkopierbare Objekte als Wert zu übergeben.

    Lies dir vielleicht die Artikelserie auf C++Next durch, da wird Move-Semantik gut erklärt.



  • Es war doch genau die Frage, wie man ein Objekt per Value über geben kann, dass nicht kopiert werden kann.

    In dem man nicht den Kopierkonstruktor involviert, sondern den Move-Konstruktor. Wenn du ein rvalue- unique_ptr an die Funktion übergibst, dann wird ebenjener aufgerufen, und der als deleted definierte Kopierkonstruktor hat nix zu suchen.



  • Das ist alles verdammt kompliziert mit der move Semantik und rvalues. Ich dachte ich hätte das halbwegs verstanden aber es ist doch nicht so 😞 Zumindest waren eure Erklärungen jetzt bei mehrfachen lesen ein bisschen erhellend.



  • Vielleicht hilft dir ja ein älterer Beitrag von mir.


Anmelden zum Antworten