unique_ptr per rvalue-Ref oder Value übergeben?



  • Ganz doofe Frage aber stehe gerade auf dem Schlauch 😕
    Wenn ich ne Funktion schreibe, dann ist es doch egal, ob ich einen unique_ptr als Rvalue-Ref oder Value übergebe, oder? Sehe grad echt nicht wo der Unterschied liegt. (Vorausgesetzt, die Funktion nutzt den Pointer in jedem Fall)
    Wie macht ihr das?



  • Wenn die Funktion den Besitz übernehmen soll, dann als unique_ptr und beim Aufruf gegebenenfalls std::move. Andernfalls nimmt die Funktion eine Referenz auf den Typ oder einen rohen Zeiger, aber niemals eine Referenz auf den unique_ptr.



  • Zum Unterschied:

    #include <memory>
    #include <iostream>
    
    using namespace std;
    
    void a(unique_ptr<int> u) {}
    void b(unique_ptr<int> &&u) {}
    
    int main() {
        auto ap = make_unique<int>(42);
        a(move(ap));
        cout << (bool) ap << '\n';
        auto bp = make_unique<int>(42);
        b(move(bp));
        cout << (bool) bp << '\n';
    }
    

    Bei b weißt du nicht, was mit der Ownership passiert - wenn die Funktion leer ist, passiert zum Beispiel gar nichts, obwohl es wegen des "move(bp)" so scheint, als würde der Owner transferiert werden. Bei a ist klar, dass Ownership transferiert wird. Daher nimm a.


  • Mod

    der Zeigermann schrieb:

    Ganz doofe Frage aber stehe gerade auf dem Schlauch 😕
    Wenn ich ne Funktion schreibe, dann ist es doch egal, ob ich einen unique_ptr als Rvalue-Ref oder Value übergebe, oder? Sehe grad echt nicht wo der Unterschied liegt. (Vorausgesetzt, die Funktion nutzt den Pointer in jedem Fall)
    Wie macht ihr das?

    Es kommt darauf an, was "in jedem Fall" bedeuten soll. Falls deine Funktion keine Exceptions werfen kann, bevor der Zeiger konsumiert wurde, hat die Wahl der Parameters keine echte Auswirkung auf den Programmverlauf. Sobald Exceptions ins Spiel kommen, musst du wissen, ob es ok ist, die übergebene Ressource zu zerstören, obwohl sie nicht konsumiert wurde. Im Allgemeinen ist dass nicht etwas, was die aufgerufene Funktion allein entscheiden kann, deshalb würde ich eine Referenz generell vorziehen (wenn keine Exceptions auftreten, spielt die Wahl ja sowieso keine Rolle) und nur dann per-Value übergeben, wenn der semantische Unterschied ausdrücklich gewünscht ist.

    Eine Funktion, die per-Value übernimmt, könnte theoretisch etwas schneller sein, weil eine Indirektion vermieden wird.

    wob schrieb:

    Bei b weißt du nicht, was mit der Ownership passiert - wenn die Funktion leer ist

    Wenn b leer ist, hast du ganz andere Probleme: dann macht die Funktion nämlich ohnehin nicht, was sie tun soll. Diese Möglichkeit hat der TE ja ausdrücklich ausgeschlossen.



  • camper schrieb:

    wob schrieb:

    Bei b weißt du nicht, was mit der Ownership passiert - wenn die Funktion leer ist

    Wenn b leer ist, hast du ganz andere Probleme: dann macht die Funktion nämlich ohnehin nicht, was sie tun soll. Diese Möglichkeit hat der TE ja ausdrücklich ausgeschlossen.

    Gut, dann ersetze meine leeren Funktionen durch cout << *u << '\n'; - dann wird der Pointer benutzt - ändert doch nichts an dem generellen Problem.


  • Mod

    Falls deine Funktion keine Exceptions werfen kann, bevor der Zeiger konsumiert wurde, hat die Wahl der Parameters keine echte Auswirkung auf den Programmverlauf.

    Edit: Du meinst, dass b das Ownership nehmen soll. Das ist aber nicht durch den Eingangspost klar gestellt.


Log in to reply