"movable" STL buffer?



  • Hallo,

    in meinen Klassen mit Pointern als Member scheint es zwei Arten von Pointern zu geben:

    • (a) Pointer, die auf eigenen Speicher zeigen (typischerweise sowas wie ein Array, das im Konstruktor mit new reserviert wird und im Destruktor wieder delete d wird)
    • (b) Pointer, die auf "außer-Klassen"-Speicher zeigen, zB auf die Programm-Konfiguration

    Der Hauptgrund, Copy Konstruktoren zu überladen, erscheint mir zu sein, weil der Compiler (a) und (b) nicht unterscheiden kann. Im Fall von (a) muss der Speicher dupliziert werden. In C++11 scheint aus der "rule of 3" die "rule of 5" geworden zu sein, sodass ich oft auch noch Move Konstruktoren schreiben sollte. Um diesen "manuellen" Aufwand zu umgehen, suche ich nun sowas wie einen STL "buffer", der einen Speicherbereich verwaltet und dessen Länge kennt, und der passend überladene Konstruktoren und Asignment Operatoren mitbringt. Dort sind mir string und vector<char> eingefallen. Mit meinem Code habe ich aber Bauchschmerzen, hier ein Bsp.

    string line;
    line.resize(line_len);
    char* buffer = const_cast<char*>(line.data());
    some_file.getline(buffer, line_len);
    

    Ich brauche einen nicht- const anten char* pointer für manche Funktionen wie eben getfile() (oder wenn ich rohe Daten aus dem Netzwerk bekomme etc.)
    Was mir nicht gefällt:

    • Ich greife "an der Klasse" vorbei direkt auf den Speicher zu.
    • Ich kann die String-Länge nicht manuell setzten. Daraus ergibt sich: Wenn ich statt string::resize() nur string::reserve() verwende, wird die String-Länge nicht angepasst (weil ich ja direkt in den Speicher schreibe). Die Länge ist aber wichtig. string::resize() "initialisiert" (d.h. "nullt") den Speicher von der aktuellen Länge bis zur neuen größeren Länge - das ist etwas, was ich für meinen Buffer nicht brauche.

    Mit vector<char> habe ich die gleichen Sorgen, zumal mir hier der C++ Standard auch nicht garantiert, dass & vector<char>::front() bedenkenlos nach char* gecastet werden kann (obwohl in der Praxis die Implementierungen der STL das erlauben). Ich könnte natürlich erst einen char -Buffer reservieren, dann dort hineinschreiben lassen, dann diesen Buffer einen Vector kopieren und dann den char -Buffer wieder freigeben, aber das ist mindestens ein Kopieren zu viel (und Speicher-Verschwendung). Das ist alles nicht so richtig schön. Hat jemand eine Idee, wie ich das besser machen könnte?

    Lars



  • 1. es gibt std::getline, um direkt in einen std::string zu lesen
    http://www.cplusplus.com/reference/string/getline/

    2. das ist ausdrücklich vorgesehen:

    std::vector<char> v;
    ...
    v.resize(20);
    ...
    read( fd, &v[0], v.size() );
    


  • Laut C++11 müssen sowohl std::string als auch std::vector<char> ihren Speicher sequenziell anfordern, insofern sehe ich dein Problem nicht. Pointer bekommst du mit &v[0] ohne Probleme. Wobei ich bei dem string eher die richtige Überladung für getline wählen würde, dann wird die Größe automatisch angepasst. Überhaupt frage ich mich wie du ohne vector und string C++ programmiert hast. oO



  • Lawilog schrieb:

    string line;
    line.resize(line_len);
    char* buffer = const_cast<char*>(line.data());
    some_file.getline(buffer, line_len);
    

    Aua. RTFM.

    Lawilog schrieb:

    Mit vector<char> habe ich die gleichen Sorgen, zumal mir hier der C++ Standard auch nicht garantiert, dass vector<char>::front() bedenkenlos nach char* gecastet werden kann (obwohl in der Praxis die Implementierungen der STL das erlauben).

    Doch!



  • Oh okay, std::getline lässt istream::getline natürlich zu einem schlechten Bsp. werden. Thx.

    @manni66: hast du für diese read unter "2." einen Link?

    TyRoXx schrieb:

    Lawilog schrieb:

    ...zumal mir hier der C++ Standard auch nicht garantiert, dass vector<char>::front() bedenkenlos nach char* gecastet werden kann (obwohl in der Praxis die Implementierungen der STL das erlauben).

    Doch!

    Ich meine, dass ist nicht der Fall. Ist aber auch nur ein theoretisches Problem. In der Praxis gibt's glaube nur Diskussionen, was passiert wenn vector.empty() ist (und man debuggt oder so).



  • Lawilog schrieb:

    @manni66: hast du für diese read unter "2." einen Link?

    Damit ist das ganz normale read für Filedescriptoren (und zumindest auf Unix auch Socketdescriptoren) gemeint. Meine Aussage ist aber allgemein auf alle Funktionen anwendbar, die einen char*-Buffer erwarten.



  • manni66 schrieb:

    Lawilog schrieb:

    @manni66: hast du für diese read unter "2." einen Link?

    Damit ist das ganz normale read für Filedescriptoren (und zumindest auf Unix auch Socketdescriptoren) gemeint. Meine Aussage ist aber allgemein auf alle Funktionen anwendbar, die einen char*-Buffer erwarten.

    OK. Dann muss ich trotzdem noch vorher resize n statt bloß reserve n (weil sich durch das read() nicht die length() von vector oder string ändert). Aber nagut, ich denke damit kann ich leben.

    Danke Leute! 🙂



  • Lawilog schrieb:

    Ich meine, dass ist nicht der Fall. Ist aber auch nur ein theoretisches Problem. In der Praxis gibt's glaube nur Diskussionen, was passiert wenn vector.empty() ist (und man debuggt oder so).

    Wenn du glauben willst such dir eine Religion.

    n3242 23.3.6.1/1 schrieb:

    The elements of a
    vector are stored contiguously, meaning that if v is a vector<T, Allocator> where T is some type other
    than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().

    n3242 21.4.1/5 schrieb:

    The char-like objects in a basic_string object shall be stored contiguously. That is, for any basic_string
    object s, the identity &*(s.begin() + n) == &*s.begin() + n shall hold for all values of n such that 0
    <= n < s.size().

    Und wenn der vector leer ist willst du wohl auch eher nicht die Adresse auf seinen Speicher haben. 😉



  • Übrigens, da es ja um C++11 geht: statt &vec[0] oder &vec.front() gibts auch für vector inzwischen die passende Methode: vec.data()



  • pumuckl schrieb:

    vec.data()

    Aber ein string Äquivalent leider nicht, str.data() gibt immer noch einen const char* zurück.


Log in to reply