smart_pointer Handhabung



  • Auf Grund folgendem Zitats aus dem Thread http://www.c-plusplus.net/forum/319812, würde ich da gerne ein wenig drüber diskutieren.

    sharry schrieb:

    Und was soll

    void Test2(SharedPtr<Base> test)
    

    sein?

    ÜBERGEBE NIE SMARTPOINTER ALS ARGUMENT (wenn du nicht weisst, was du tust)!

    Das sollte

    void Test2(Base const& test)
    

    sein und dann ist dein Problem gelöst.

    Handhabt ihr das alle so, das ihr nur Referenzen auf das Object übergebt und keine Referenzen auf den SmartPointer an sich?
    Wenn ja, aus welchem Grund? Das man einen Unique_ptr nicht ohne weiteres übergeben kann, ist mir bewusst, aber eine (const) Referenz darauf ist möglich. Und so handhabe ich das eigentlich auch.

    mfg



  • Das ist Bloedsinn. Wenn Besitz uebergeben werden soll, dann Smartpointer per const ref im Falle von Reference Counting, bei unique_ptr per Value. Wenn nicht, dann per (const) ref.



  • Warum sollte der Smart-Pointer Teil der Schnittstelle sein, wenn man mit ihm nix weiter anfangen will?
    Entweder man will Ownership ausweiten (oder das zumindest zulassen), es abtreten, oder der Smart-Pointer hat in der Signatur nix zu suchen.



  • Kellerautomat schrieb:

    bei unique_ptr per Value. Wenn nicht, dann per (const) ref.

    Einen unique_ptr per Value übergeben? Wie geht das denn? Kopieren geht doch nicht... oO
    Oder meinst du moven?!
    Und statt const& kann man auch gleich ne normale Referenz auf das Objekt nehmen.



  • Das geht genau so, wenn man unique_ptr per Wert nimmt, dann klappt das nur mit einer R-Value als Argument, aus der auf jedem Fall heraus-gemoved wird und daher zeigt dieser Art der Übergabe dem Benutzer unmissverständlich, dass hier ein Ownership-Transfer stattfindet.



  • Die Aussage ist, dass wenn es möglich ist die Funktion mit einer const-Referenz auf das Objekt zu implementieren, das dann auch der beste Weg ist.

    Nur in seltenen Fällen braucht man shared_ptr<Object> const& oder unique_ptr<Object> (ja, das geht). In ganz seltenen Fällen, wenn man den Smartpointer ändern will, braucht man shared_ptr<Object>& oder unique_ptr<Object>& .

    unique_ptr<Objekt> const& hingegen macht kein Sinn. Hat keinerlei Vorteile gegenüber Object* / Object const* / Object& / Object const& , nur Nachteile.



  • sharry schrieb:

    Die Aussage ist, dass wenn es möglich ist die Funktion mit einer const-Referenz auf das Objekt zu implementieren, das dann auch der beste Weg ist.

    Und das ist einfach falsch.
    Es sind verschiedene Dinge: Entweder ich uebergebe Besitz, oder eben nicht. Je nachdem entscheidet man.



  • Kellerautomat schrieb:

    sharry schrieb:

    Die Aussage ist, dass wenn es möglich ist die Funktion mit einer const-Referenz auf das Objekt zu implementieren, das dann auch der beste Weg ist.

    Und das ist einfach falsch.
    Es sind verschiedene Dinge: Entweder ich uebergebe Besitz, oder eben nicht. Je nachdem entscheidet man.

    Stimmt so doch.

    Ist es möglich übergebenden Besitz mit einer const-Referenz zu implementieren? Nein. Also Referenz auf Smartpointer.



  • Skym0sh0 schrieb:

    Einen unique_ptr per Value übergeben? Wie geht das denn? Kopieren geht doch nicht... oO

    Das hier funzt by design:

    #include <iostream>
    #include <memory>
    
    using std::unique_ptr;
    
    unique_ptr<int> source()
    {
       unique_ptr<int> p (new int(42));
       return p;
    }
    
    void sink(unique_ptr<int> p)
    {
       std::cout << "*p is " << *p << '\n';
    }
    
    int main()
    {
      sink(source());
    }
    

    und das ist gut so.



  • Ok, danke für die Nachhilfe 😉



  • Kellerautomat schrieb:

    Wenn Besitz uebergeben werden soll, dann Smartpointer per const ref im Falle von Reference Counting, bei unique_ptr per Value. Wenn nicht, dann per (const) ref.

    wobei seit move semantics ich auch einen shared_ptr per value übergeben würde. Wenn also der "Besitz" übergeben wird und die Funktion den shared_ptr irgendwo anders speichern will, dann hast du bei folgenden Möglichkeiten

    • ref-auf-const
    • ref-auf-const und rvalue-ref überladen
    • pass by value

    beim letzten Punkt keine unnötigen Kopien (die Funktion kann den shared_ptr dahin moven, wo sie ihn haben will) und das ohne dass man die funktion überladen muss. Das Moven eines shared_ptrs ist, denke ich mal, vernachlässigbar. Jedenfalls muss da der Referenzzähler nicht angefasst werden.

    Statt einer Referenz in anderen Fällen finde ich u.U. einen Zeiger auch sinnvoll. Was ich da nehme hängt u.a. davon ab, ob ich möchte, dass man beim Aufruf der Funktion sehen kann, dass ein Objekt nicht per Wert übergeben wird. Das ist ja im Falle von Referenzen nicht so offensichtlich, wenn man die Deklaration der Funktion nicht vor Augen hat. Und das möchte ich typischerweise dann, wenn die Funktion die Adresse des Objekts für länger irgendwo speichert -- nicht "besitzend" sondern nur "kennend"; denn ich erwarte i.A. nicht, dass eine Funktion, die eine Referenz entgegen nimmt, die Adresse des Objekts irgendwo speichert. Offensichtliche Ausnahme ist std::ref und std::cref, wobei das da allerdings klar sein dürfte, was sie macht.



  • Warum moven, wenn mans fuer lau bekommen kann? Sinnlos.



  • Kellerautomat schrieb:

    Warum moven, wenn mans fuer lau bekommen kann? Sinnlos.

    Du scheinst da nur an einen bestimmten Fall zu denken, nämlich den, in dem das Funktionsargument ein Lvalue ist. In dem Fall hätte man bei pass-by-value ein zusätzliches Move. Ein Move ist allerdings billig. Wenn das Argument ein Rvalue ist, hast du in deinem ref-auf-const Fall eine unnötige Kopie. Eine Kopie ist teuerer. Möchtest du, dass ich dazu ein Beispiel schreibe und erkläre in welcher Situation was wo kopiert und gemoved wird, oder glaubst du mir das jetzt auch so? Vielleicht denkst du ja selbst nochmal ein bisschen drüber nach. Die Fälle, die unterschieden werden sollten, sind:

    • Argument ist ein Lvalue
    • Argument ist ein Rvalue, Compiler führte copy-elision durch
    • Argument ist ein Rvalue, Compiler hat die copy-elision nicht hinbekommen

    Die optimale Lösung im Sinne der Reduzierung von unnötigen Kopien und Moves bekommst du nur mit der Überladung ref-auf-const und rvalue-ref. Allerdings spare ich mir gerne die Überladung und nehme ein ggf. unnötiges Move bei pass-by-value in Kauf. Klar soweit?


Anmelden zum Antworten