std::string Speicherdarstellung - mit char* überschreiben?
-
Shade Of Mine schrieb:
cooky451 schrieb:
In C++11 muss der Speicher zusammenhängend sein, das heißt bei entsprechender Größe darfst du auch rein schreiben. Zeiger würde ich mir über &*begin() holen.
Würde ich aber davon abraten. Weil du mit resize vorher die größe festlegen musst und dann ist die Frage, warum nicht gleich mit assign() arbeiten?
Also lieber in char* und dann mit assign() ?
Hatte vorher resize() aufgerufen und dann direkt nach str.data() reinkopiert.
-
Shade Of Mine schrieb:
Würde ich aber davon abraten. Weil du mit resize vorher die größe festlegen musst und dann ist die Frage, warum nicht gleich mit assign() arbeiten?
Weil er dann eine unnötige Kopie machen muss? Und warum assign, dann kann er auch gleich operator = nehmen..
-
[quote="cooky451"]
Shade Of Mine schrieb:
Weil er dann eine unnötige Kopie machen muss?
Genau deshalb habe ich gleich in den std::string reinkopiert.

-
cooky451 schrieb:
Weil er dann eine unnötige Kopie machen muss?
Wo muss er das? Seh ich nicht ganz ein.
Nehmen wir mal an er will irgendeine Sequenz von chars von irgendwo in den string kopieren, dabei vielleicht nur einen Teil des strings überschreiben.
Dann macht string::replace das was er möchte

-
pumuckl schrieb:
cooky451 schrieb:
Weil er dann eine unnötige Kopie machen muss?
Wo muss er das? Seh ich nicht ganz ein.
Tut mir Leid, ich kenne keine Möglichkeit, außer direkt in den std::string zu schreiben - und ich denke auch nicht, dass es eine gibt. Wenn du eine kennst, bitte ich dich darum sie zu präsentieren.
-
cooky451 schrieb:
Tut mir Leid, ich kenne keine Möglichkeit, außer direkt in den std::string zu schreiben - und ich denke auch nicht, dass es eine gibt. Wenn du eine kennst, bitte ich dich darum sie zu präsentieren.
Siehe mein edit oben - replace deckt alles ab was ich mir in der Richtung vorstellen kann

-
Das Ganze wird direkt an einen Stream übergeben. Das kann alles mögliche sein, in der Regel aber ein Socket.
Der schreibt dann unmittelbar in einen Speicherbereich rein.
Deshalb habe ich auch mit &(string[0]) direkt einen Zeige darauf übergeben und reinschreiben lassen.
Sonst müsste ich zunächst mit new char[] mit Speicher holen, dann dort reinschreiben lassen und am Ende mit assign(), replace() oder sonstwas kopieren.
-
pumuckl schrieb:
Siehe mein edit oben - replace deckt alles ab was ich mir in der Richtung vorstellen kann

Dann wolltest du wohl noch nie von einer C-API aus etwas in einen String schreiben.

-
cooky451 schrieb:
pumuckl schrieb:
Siehe mein edit oben - replace deckt alles ab was ich mir in der Richtung vorstellen kann

Dann wolltest du wohl noch nie von einer C-API aus etwas in einen String schreiben.

Weil man dafuer auch nicht std::string verwendet.
Wenn es eine C API ist, dann ist std::vector besser als std::string, bzw. hat man fuer sowas eine eigene string Klasse.
Direkt in den String schreiben ist unschoen und wird von reiner C API ja auch nicht direkt unterstuetzt - da man vorher die exakte groesse wissen muss. Oder natuerlich man macht 2 mal resize.
Ne ne, std::string und C APIs mixen ist ungut.
-
cooky451 schrieb:
Dann wolltest du wohl noch nie von einer C-API aus etwas in einen String schreiben.

Stimmt, auf so einen unsinnigen Gedanken bin ich nie gekommen
Einer C-API gebe ich nur Dinge, mit der eine C-API auch zurechtkommt - strings gehören nicht dazu 
-
Er serialisiert, dh. die Daten kommen aus einem Stream.
std::istream::read nimmt ein char* als Destination.
Ohne direkt reinschreiben muss er Kopien erzeugen.
-
Dann aber bitte in ein std::vector<char> und nicht in ein std::string.
Zumal (entegegen Behauptungen in diesem Thread) das interne Memory von std::string in C++03 nicht zusammenhängend sein muss. Ab C++11 ist das so - vorher muss es nicht.
-
theta schrieb:
Dann aber bitte in ein std::vector<char> und nicht in ein std::string.
Zumal (entegegen Behauptungen in diesem Thread) das interne Memory von std::string in C++03 nicht zusammenhängend sein muss. Ab C++11 ist das so - vorher muss es nicht.Dann hat man aber ein Kopie. Und wieso sollte man mit C++11 nicht direkt in den String schreiben? Spricht ja nichts dagegen.
-
Ethon schrieb:
theta schrieb:
Dann aber bitte in ein std::vector<char> und nicht in ein std::string.
Zumal (entegegen Behauptungen in diesem Thread) das interne Memory von std::string in C++03 nicht zusammenhängend sein muss. Ab C++11 ist das so - vorher muss es nicht.Dann hat man aber ein Kopie. Und wieso sollte man mit C++11 nicht direkt in den String schreiben? Spricht ja nichts dagegen.
Doch, natürlich mit C++11 schon, nur nicht mit C++03.
-
Ethon schrieb:
Er serialisiert, dh. die Daten kommen aus einem Stream.
std::istream::read nimmt ein char* als Destination.
Ohne direkt reinschreiben muss er Kopien erzeugen.Das ist falsch. Ich kann hier sehr wohl ohne Kopie std::string verwenden. Je nachdem wie ich serialisiere rufe ich vorher ein reserve auf und dann push_back. Wenn es eine C++ API geht das auch super mit einem insert iterator.
Sprich: wenn die SerialisierungsAPI eine C++ API ist, ists easy.
Wenn die SerialisierungsAPI eine C API ist, ist std::string eine schlechte Idee. Dann macht man 1 resize, kopiert in den std::string und macht nachher noch ein resize. Aber das ist böse und sollte nur als unbedingter Notfall gemacht werden.
Besser ist natürlich wenn ich statt einem char* zu übergeben nur einen char bekommen kann, dann kann ich das auch mit std::string und push_back easy machen. Jede File API bietet ein get() an dass nur 1 Byte liefert. Die File API selber puffert ja sowieso, ich muss also nicht unbedingt große Chunks lesen.
Wenn möglich natürlich eine C++ API verwenden oder eine C API Kompatible String Klasse.
-
Ich denke, ihr redet aneinander vorbei. Was Ethon wahrscheinlich meint ist Folgendes (bei mir ist dies eine Klasse zum Lesen von einfachen Binärdateien, bei denen die Reihenfolge bekannt ist):
BinaryIStream &operator>>(std::string &s) // operator für alles überladen, hier string { unsigned len; *this>>len; // Länge (32 Bit) wird immer vor den String geschrieben (ohne Nullterminierung) std::vector<char> buff(len+1); // Umweg über vector in C++ 03 nötig read(&buff[0], static_cast<std::streamsize>(len)); s=&buff[0]; // Zuweisung (die besschriebene Kopie) return *this; }Mit den Garantien des neuen Standards bezüglich strings ließe sich das Ganze eben noch verbessern.
-
Der Code ist nicht gut, weil unnoetige Kopien.
BinaryIStream &operator>>(std::string &s) // operator für alles überladen, hier string { unsigned len; *this>>len; // Länge (32 Bit) wird immer vor den String geschrieben (ohne Nullterminierung) s.reserve(len); while(len--) char c; read(&c, 1); s.push_back(c); } return *this; }In C++11 kann man durch das move natuerlich eine Kopie sparen, aber wozu das ganze so umstaendlich machen?
btw wurde in deinem Code zB die nullterminierung des strings vergessen. Oder nullt der vector alle Elemente? Das waere ja noch lahmer...
-
BinaryIStream &operator>>(std::string &s) // operator für alles überladen, hier string { unsigned len; *this>>len; // Länge (32 Bit) wird immer vor den String geschrieben (ohne Nullterminierung) s.resize(len); read(&s[0], len); return *this; }So wärs deutlich schneller.
Oder nullt der vector alle Elemente? Das waere ja noch lahmer...
Ja, sie werden default konstruiert.
-
unsigned ist schonmal, was binäres lesen angeht, Gift für Plattformunabhängigkeit. Entweder uint16_t oder uint32_t, wobei ich nicht glaube das jemand mehr als 65535 Zeichen in einen String stecken möchte.
-
Ethon schrieb:
BinaryIStream &operator>>(std::string &s) // operator für alles überladen, hier string { unsigned len; *this>>len; // Länge (32 Bit) wird immer vor den String geschrieben (ohne Nullterminierung) s.resize(len); read(&s[0], len); return *this; }So wärs deutlich schneller.
Exakt so mache ich es auch beim std::string derzeit! Zuerst ein full-resize und dann direkt reinkopieren lassen. Die festen 32-Bit geben die Länge zu Beginn an und werden jeweils in little-endian oder big-endian übertragen.
std::wstring behandle ich anders.