Adresse des internen pointers von unique_ptr



  • Hallo,

    ich möchte eine Funktion einer C Api benutzen. Als Argument wird die Addresse eines pointers erwartet. Normalerweise wird die Funktion so aufgerufen:

    some_type * x;
    
    function(&x);
    

    Ich habe jetzt einen unique_ptr, der mein x verwaltet:

    std::unique_ptr<some_type, decltype(&my_deleter)> ptr(x, my_deleter);
    

    Wenn ich jetzt versuche, die Funktion aufzurufen, gibt es einen Fehler:

    function(&ptr.get())
    //Fehler: Addressoperator auf R-Value angewendet
    

    Das klingt eigentlich nach einem Standardproblem. Gibt es eine Möglichkeit, das als Einzeiler zu lösen? Direkt an den Internen Pointer kommt man ja nicht...


  • Mod

    Wenn die C-Funktion die Adresse des Pointers möchte, wird das doch sicherlich den Grund haben, dass sie diesen Wert ändern möchte. In dem Fall wäre ein unique_ptr nicht geeignet.



  • Gutes Argument. Dann halt ohne unique pointer 🙂


  • Mod

    asdfasd schrieb:

    Gutes Argument. Dann halt ohne unique pointer 🙂

    Und guck dir unbedingt an, was die Funktion überhaupt genau macht. Klingt so, als wäre dir das im Moment selbst nicht so ganz klar.

    Ist das eine Art Konstruktor, der dir ein Handle zurück gibt, das du dann in dem unique_ptr speichern möchtest?



  • Ist nur eine Übungsaufgabe für die Uni. Den Quellcode der Funktion habe ich nicht, aber laut Dokumentation ändert die Funktion den Pointer nicht, von daher wäre es wahrscheinlich OK. Trotzdem hast du natürlich recht, dem unique_ptr potentiell die Kontrolle über seine Ressource zu nehmen, ist nicht gut. Aufgabe ist, den pointer als Member einer C++-Klasse zu machen und mit einem C-Interface zu interagieren. Der ganze Kontext sieht ungefähr so aus:

    //C Api
    void do_something(some_type **);
    
    some_type* allocate_some_type(args...);
    
    void delete_some_type(some_type*);
    
    //C++ part - so wollte ich es machen
    class Class
    {
    public:
        unique_ptr<some_type, decltype(&delete_some_type)> ptr;
    
        Class(args)
            : ptr(allocate_some_type(args), delete_some_type)
        {}
    };
    
    // irgendwann speater im code:
    Class c(args);
    do_sutff( &c.ptr.get() );
    
    // C++ part - so mache ich es jetzt
    class Class
    {
    public:
        some_type* ptr;
    
        Class(args)
            : ptr(allocate_some_type(args))
        {}
        // freigabe der ressource im Destruktor anstatt ueber unique_ptr
        ~Class() { delete_some_type(ptr); }
    }
    
    // irgendwann speater im code:
    Class c(args);
    do_sutff( &c.ptr );
    

    Ich denke das wird der Aufgabe so gerechet.


  • Mod

    Komische Schnittstelle. Das mit dem allocate_some_type und dem delete_some_type ist, wie ich es mir vorgestellt habe. Das do_something fällt dann plötzlich aus der Reihe.

    Das do_stuff soll doch sicherlich ein Member der Class sein.

    Denk bei deiner Lösung ohne unique_ptr an die Regel der großen Drei.



  • "do_something" schreibt in meinem Fall einfach ein paar Informationen über "some_type" in die Konsole (wie gesagt, auf die Definition von "do_something" habe ich keinen Einfluss). Ich kann natürlich eine Art Wrapper dafür in die Klasse bauen:

    class Class
    {
        some_type* ptr = nullptr;
    
    public:
        Class(args)
            : ptr(allocate_some_type(args))
        {}
    
        // der "Wrapper"
        void print() { do_something(&ptr); }
    
        // freigabe der ressource im Destruktor anstatt ueber unique_ptr
        ~Class()
        {
            if(ptr)
                delete_some_type(ptr);
        }
    
        // ist nur eine Uebung. Regel der grossen drei/fuenf nicht wichtig :D
        Class& operator=(const Class&) = delete;
        Class& operator=(Class&&) = delete;
        Class(const Class&) = delete;
        Class(Class&&) = delete;
    }
    
    // irgendwann speater im code:
    Class c(args);
    c.print();
    

    Meinst du so?


  • Mod

    Ja. Ich kenne natürlich nicht die genaue Aufgabenstellung, aber von

    Aufgabe ist, den pointer als Member einer C++-Klasse zu machen und mit einem C-Interface zu interagieren.

    her würde ich annehmen, dass das so gemeint ist.

    PS: Die Regel der großem Drei/Fünf ist immer wichtig, wenn du Ressourcen verwaltest. Das Kopieren zu verbieten, wie du es hier machst, kann eine richtige und sinnvolle Anwendung der Regel sein. Jedenfalls ist es sehr wichtig, dass dein Code die Problematik irgendwie handhabt, sonst kommst du ganz schnell in Probleme.



  • Ok, ich denke die Lösung ist so in Ordnung. Danke für deine Tipps!


Anmelden zum Antworten