SQLite - unique_ptr



  • Hi,

    ich arbeite mich im Moment in SQLite ein.

    Meine Frage hat aber eher weniger mit SQLite zutun, sondern eher allgemein mit Smartpointern:

    Wie greife ich auf das eigendliche Objekt hinter einem SmartPointer zu?

    std::unique_ptr<sqlite3> Database;
    
    [...]
    
    //Hier komme ich nicht weiter...
    int rc = sqlite3_open_v2(filename.c_str(), &this->Database, flags, NULL);
    LastError =(std::string)sqlite3_errmsg(this->Database);
    

    Die Fehlermeldung ist immer

    IntelliSense: Es ist keine passende Konvertierungsfunktion von ""std::unique_ptr<sqlite3, std::default_delete<sqlite3>>"" in ""sqlite3 *"" vorhanden.

    Kann mir da jemand weiterhelfen?


  • Mod

    Auf den Inhalt eines Smart-Pointers greift man mit der get -Memberfunktion zu, hier wäre das std::unique_ptr::get. Auf den Pointee greift man wie gewohnt über den (für Smart-Pointer überladenen) *-Operator oder ->-Operator zu.

    Dein Code hat aber das Problem dass sqlite3_open_v2 einen Zeiger auf den Zeiger erwartet. Man kann den internen Zeiger eines Smart-Pointers aber nicht direkt anfassen. Da musst du irgendwie einen Zeiger zum Zwischenspeichern verwenden.



  • Hi,

    error C2664: 'sqlite3_open_v2': Konvertierung des Parameters 2 von 'std::unique_ptr<_Ty> *' in 'sqlite3 **' nicht möglich

    error C2664: 'sqlite3_errmsg': Konvertierung des Parameters 1 von 'std::unique_ptr<_Ty>' in 'sqlite3 *' nicht möglich


  • Mod

    Probier es mal so

    sqlite3* ptr;
    int rc = sqlite3_open_v2(filename.c_str(), &ptr, flags, NULL);
    Database.reset(ptr);
    
    LastError =(std::string)sqlite3_errmsg(Database.get()); // Das sollte funktionieren
    


  • Was willst du denn da mit einem unique_ptr? Du musst zum Freigeben die passende sqlitv3_close-Funktion verwenden!



  • LastError =(std::string)sqlite3_errmsg(Database.get());
    

    Das passt so mit Sicherheit auch nicht. Und wenn´s doch funktioniert hast du Glück mit der Implementation, aber darauf würde ich nicht nicht verlassen. sqlite3_errmsg liefert etwas zurück, was sich in einen std::string konvertieren lässt, aber es ist mit Sicherheit kein std::string .


  • Mod

    DocShoe schrieb:

    LastError =(std::string)sqlite3_errmsg(Database.get());
    

    Das passt so mit Sicherheit auch nicht. Und wenn´s doch funktioniert hast du Glück mit der Implementation, aber darauf würde ich nicht nicht verlassen. sqlite3_errmsg liefert etwas zurück, was sich in einen std::string konvertieren lässt, aber es ist mit Sicherheit kein std::string .

    😕 Es liefert einen char const* zurück. Kein void const* , wie sqlite3_errmsg16 . Dann wird ein std::string mit dem zurückgegebenen, nullterminiertem(?) String initialisiert. Wo genau liegt das Problem, übersehe ich etwas?



  • manni66 schrieb:

    Was willst du denn da mit einem unique_ptr? Du musst zum Freigeben die passende sqlitv3_close-Funktion verwenden!

    Auch in dem Fall ist ein unique_ptr hilfreich. Man muss nur die sqlitv3_close-Funktion als custom deleter verwenden.



  • Arcoth schrieb:

    DocShoe schrieb:

    LastError =(std::string)sqlite3_errmsg(Database.get());
    

    Das passt so mit Sicherheit auch nicht. Und wenn´s doch funktioniert hast du Glück mit der Implementation, aber darauf würde ich nicht nicht verlassen. sqlite3_errmsg liefert etwas zurück, was sich in einen std::string konvertieren lässt, aber es ist mit Sicherheit kein std::string .

    😕 Es liefert einen char const* zurück. Kein void const* , wie sqlite3_errmsg16 . Dann wird ein std::string mit dem zurückgegebenen, nullterminiertem(?) String initialisiert. Wo genau liegt das Problem, übersehe ich etwas?

    Nach dem zweiten mal drüber nachdenken hast du recht. Ich bin irgendwie davon ausgegangen, dass sich der C-Style cast wie ein reinterpret_cast verhält, und dann wäre das Verhalten implementationsabhängig.



  • DocShoe schrieb:

    Nach dem zweiten mal drüber nachdenken hast du recht. Ich bin irgendwie davon ausgegangen, dass sich der C-Style cast wie ein reinterpret_cast verhält, und dann wäre das Verhalten implementationsabhängig.

    Ist meier Meinung nach auch eher unschöner Code Ich hätte eher etwas geschrieben wie

    LastError = std::string{sqlite3_errmsg(Database.get()};
    

  • Mod

    Wozu denn ueberhaupt ein Cast, ist er wirklich noetig? Und warum 'Uniform Initialization', TNA?

    @DocShoe: Ist dir die Semantik von C-Style Casts in C++ klar? Sie haben das gleiche Verhalten wie ein static_cast , falls moeglich. Nur falls dieser nicht anwendbar ist kommt reinterpret_cast zum Einsatz. (Das ist nicht ganz korrekt, aber ich werde nicht eine Beschreibung die const_cast beinhaltet auf einem alten Blackberry schreiben, das ist pure Folter :D)



  • Arcoth schrieb:

    Wozu denn ueberhaupt ein Cast, ist er wirklich noetig?

    Guter Punkt. Da string::string (const char* s) nicht explizit ist, sollte die Zuweisung auch ohne Cast funktionieren. Meiner Meinung nach die beste Variante.

    Arcoth schrieb:

    Und warum 'Uniform Initialization', TNA?

    Ist sicherlich Geschmackssache aber warum nicht (mal davon abgesehen, dass an der Stelle eigentlich gar keine explizite Typumwandlung nötig ist)? Ich benutze immer Uniform Initialization dort wo es möglich ist.


  • Mod

    TNA schrieb:

    Ich benutze immer Uniform Initialization dort wo es möglich ist.

    Ich hatte gehofft, das Forum haette allen derlei Schabernack ausgetrieben.



  • Arcoth schrieb:

    TNA schrieb:

    Ich benutze immer Uniform Initialization dort wo es möglich ist.

    Ich hatte gehofft, das Forum haette allen derlei Schabernack ausgetrieben.

    Eine lautstarke Minderheit überzeugt halt nicht jeden.


Anmelden zum Antworten