Gibt es eine C ++ Standard Template Library - Klasse , die eine effiziente String - Verkettung Funktionalität, ähnlich wie C # 's bietet String oder Java String ?
c++
stl
string-concatenation
An̲̳̳drew
quelle
quelle
std::ostringstream
.Antworten:
HINWEIS Diese Antwort hat in letzter Zeit einige Aufmerksamkeit erhalten. Ich befürworte dies nicht als Lösung (es ist eine Lösung, die ich in der Vergangenheit vor der STL gesehen habe). Es ist ein interessanter Ansatz , und nur dann angewandt werden , über soll
std::string
oderstd::stringstream
wenn nach dem Code Profilieren Sie entdecken , dies macht eine Verbesserung.Normalerweise benutze ich entweder
std::string
oderstd::stringstream
. Ich hatte noch nie Probleme damit. Normalerweise würde ich zuerst etwas Platz reservieren, wenn ich die grobe Größe der Saite im Voraus kenne.Ich habe in der fernen Vergangenheit gesehen, wie andere Leute ihren eigenen optimierten String-Builder hergestellt haben.
Es werden zwei Zeichenfolgen verwendet, eine für den Großteil der Zeichenfolge und die andere als Arbeitsbereich zum Verketten kurzer Zeichenfolgen. Die Anhänge werden optimiert, indem die kurzen Anhängevorgänge in einer kleinen Zeichenfolge zusammengefasst und dann an die Hauptzeichenfolge angehängt werden, wodurch die Anzahl der erforderlichen Neuzuweisungen für die Hauptzeichenfolge verringert wird, wenn diese größer wird.
Ich habe diesen Trick mit
std::string
oder nicht benötigtstd::stringstream
. Ich denke, es wurde mit einer String-Bibliothek eines Drittanbieters vor std :: string verwendet, es ist so lange her. Wenn Sie eine Strategie wie dieses Profil anwenden, verwenden Sie zuerst Ihre Bewerbung.quelle
scratch
Saite hier wirklich etwas bewirkt. Die Anzahl der Neuzuweisungen des Hauptstrings hängt weitgehend von seiner endgültigen Größe ab, nicht von der Anzahl der Anhängeoperationen, es sei denn, diestring
Implementierung ist wirklich schlecht (dh es wird kein exponentielles Wachstum verwendet). Das "Stapeln"append
hilft also nicht, denn sobald der Basiswertstring
groß ist, wächst er nur gelegentlich in beide Richtungen. Darüber hinaus werden eine Reihe redundanter Kopiervorgänge hinzugefügt und möglicherweise mehr Neuzuweisungen (daher Aufrufe vonnew
/delete
), da Sie an eine kurze Zeichenfolge anhängen.str.reserve(1024);
dass es schneller sein würde als dieses DingDer C ++ - Weg wäre, std :: stringstream oder einfach nur String-Verkettungen zu verwenden. C ++ - Zeichenfolgen sind veränderbar, sodass die Leistungsaspekte der Verkettung weniger wichtig sind.
In Bezug auf die Formatierung können Sie alle gleichen Formatierungen in einem Stream vornehmen, jedoch auf andere Weise, ähnlich wie bei
cout
. oder Sie können einen stark typisierten Funktor verwenden, der dies kapselt und eine String.Format-ähnliche Schnittstelle bereitstellt, z. B. boost :: formatquelle
StringBuilder
besteht darin, die Ineffizienz des unveränderlichen grundlegenden String-Typs von Java abzudecken . Mit anderen Worten, esStringBuilder
handelt sich um Patchwork, daher sollten wir froh sein, dass wir in C ++ keine solche Klasse benötigen.O(n)
im Allgemeinen endet .Die
std::string.append
Funktion ist keine gute Option, da sie nicht viele Arten von Daten akzeptiert. Eine nützlichere Alternative ist die Verwendungstd::stringstream
; wie so:quelle
std::string
ist das C ++ - Äquivalent: Es ist veränderlich.quelle
Sie können .append () verwenden, um Zeichenfolgen einfach zu verketten.
Ich denke, Sie könnten sogar in der Lage sein:
Was die Formatierungsvorgänge von C # betrifft
StringBuilder
, glaube ichsnprintf
(odersprintf
wenn Sie das Risiko eingehen möchten, fehlerhaften Code zu schreiben ;-)), dass die Konvertierung in ein Zeichenarray und die Rückkonvertierung in eine Zeichenfolge die einzige Option ist.quelle
Da
std::string
in C ++ veränderbar ist, können Sie das verwenden. Es hat eine+= operator
und eineappend
Funktion.Wenn Sie numerische Daten anhängen müssen, verwenden Sie die
std::to_string
Funktionen.Wenn Sie noch mehr Flexibilität in Form der Serialisierung eines Objekts in eine Zeichenfolge wünschen, verwenden Sie die
std::stringstream
Klasse. Sie müssen jedoch Ihre eigenen Streaming-Operator-Funktionen implementieren, damit sie mit Ihren eigenen benutzerdefinierten Klassen funktionieren.quelle
std :: string's + = funktioniert nicht mit const char * (was für Dinge wie "string to add" zu sein scheinen), daher ist die Verwendung von stringstream definitiv die nächste, die erforderlich ist - Sie verwenden einfach << anstelle von +
quelle
Ein praktischer String Builder für c ++
Wie viele Leute zuvor geantwortet haben, ist std :: stringstream die Methode der Wahl. Es funktioniert gut und hat viele Konvertierungs- und Formatierungsoptionen. IMO hat es jedoch einen ziemlich unangenehmen Fehler: Sie können es nicht als Einzeiler oder als Ausdruck verwenden. Sie müssen immer schreiben:
Das ist ziemlich ärgerlich, besonders wenn Sie Strings im Konstruktor initialisieren möchten.
Der Grund ist, dass a) std :: stringstream keinen Konvertierungsoperator in std :: string hat und b) die Operatoren << () des Stringstreams keine Stringstream-Referenz zurückgeben, sondern stattdessen eine std :: ostream-Referenz - die nicht weiter als String-Stream berechnet werden kann.
Die Lösung besteht darin, std :: stringstream zu überschreiben und ihm bessere Übereinstimmungsoperatoren zu geben:
Damit können Sie Dinge wie schreiben
sogar im Konstruktor.
Ich muss gestehen, dass ich die Leistung nicht gemessen habe, da ich sie noch nicht in einer Umgebung verwendet habe, in der der Stringaufbau noch stark genutzt wird, aber ich gehe davon aus, dass sie nicht viel schlimmer sein wird als std :: stringstream, da alles erledigt ist über Referenzen (außer der Konvertierung in einen String, aber das ist auch eine Kopieroperation in std :: stringstream)
quelle
std::stringstream
so verhalte.Der Seilcontainer kann sich lohnen, wenn eine Zeichenfolge in die zufällige Stelle der Zielzeichenfolge oder für lange Zeichenfolgen eingefügt / gelöscht werden muss. Hier ist ein Beispiel aus der Implementierung von SGI:
quelle
Ich wollte aus folgenden Gründen etwas Neues hinzufügen:
Bei einem ersten Versuch konnte ich nicht schlagen
std::ostringstream
'soperator<<
Effizienz, aber mit mehr Versuchen konnte ich einen StringBuilder erstellen, der in einigen Fällen schneller ist.
Jedes Mal, wenn ich eine Zeichenfolge anhänge, speichere ich irgendwo einen Verweis darauf und erhöhe den Zähler der Gesamtgröße.
Die wirkliche Art, wie ich es endlich implementiert habe (Horror!), Ist die Verwendung eines undurchsichtigen Puffers (std :: vector <char>):
für Byte []
für verschobene Zeichenfolgen (Zeichenfolgen mit angehängt
std::move
)std::string
Objekt (wir haben Eigentum)für Saiten
std::string
Objekt (kein Besitz)Es gibt auch eine kleine Optimierung: Wenn die zuletzt eingefügte Zeichenfolge verschoben wurde, sucht sie nach frei reservierten, aber nicht verwendeten Bytes und speichert dort weitere Bytes, anstatt den undurchsichtigen Puffer zu verwenden (um Speicherplatz zu sparen, wird sie tatsächlich etwas langsamer , hängt vielleicht auch von der CPU ab, und es kommt sowieso selten vor, dass Zeichenfolgen mit zusätzlichem reserviertem Speicherplatz angezeigt werden.)
Dies war schließlich etwas schneller als
std::ostringstream
, hat aber einige Nachteile:ostringstream
Fazit? verwenden
std::ostringstream
Es behebt bereits den größten Engpass, während es sich nicht lohnt, mit der Minenimplementierung einige Prozentpunkte Geschwindigkeit zu erreichen.
quelle