it-swarm.com.de

c ++ std :: ostringstream vs std :: string :: append

In allen Beispielen, die eine Art Pufferung verwenden, wird der Stream anstelle von string verwendet. Wie unterscheidet sich std :: ostringstream und << operator von der Verwendung von string.append? Welches ist schneller und welches verwendet weniger Ressourcen (Gedächtnis).

Ein Unterschied, den ich kenne, ist, dass Sie verschiedene Typen in den Ausgabestrom (wie eine Ganzzahl) ausgeben können, anstatt die begrenzten Typen, die von string :: append akzeptiert werden.

Hier ist ein Beispiel:

std::ostringstream os;
os << "Content-Type: " << contentType << ";charset=" << charset << "\r\n";
std::string header = os.str();

vs

std::string header("Content-Type: ");
header.append(contentType);
header.append(";charset=");
header.append(charset);
header.append("\r\n");

Offensichtlich ist die Verwendung von Stream kürzer, aber ich denke, dass an den String eine Referenz angehängt wird, damit sie so geschrieben werden kann:

std::string header("Content-Type: ");
header.append(contentType)
  .append(";charset=")
  .append(charset)
  .append("\r\n");

Und mit dem Ausgabestrom können Sie Folgendes tun:

std::string content;
...
os << "Content-Length: " << content.length() << "\r\n";

Aber wie steht es um Speicherplatz und Geschwindigkeit? Besonders wenn es in einer großen Schleife verwendet wird.

Update:

Um genauer zu sein, lautet die Frage: Welche sollte ich verwenden und warum? Gibt es Situationen, in denen die eine oder die andere bevorzugt wird? Für Leistung und Gedächtnis ... Nun, ich denke, Benchmark ist der einzige Weg, da jede Implementierung anders sein kann.

Update 2:

Nun, ich bekomme keine klare Vorstellung davon, was ich aus den Antworten verwenden sollte, was bedeutet, dass jeder von ihnen die Arbeit erledigen wird, plus Vektor. Cubbi hat mit dem Zusatz von Dietmar Kühl den Benchmark von Nice gesetzt, der größte Unterschied besteht in der Konstruktion dieser Objekte. Wenn Sie nach einer Antwort suchen, sollten Sie diese auch überprüfen. Ich warte noch ein wenig auf andere Antworten (siehe vorheriges Update) und wenn ich keine bekomme, akzeptiere ich die Antwort von Tolga, da sein Vorschlag, vector zu verwenden, bereits gemacht wurde.

26
NickSoft

std::ostringstream wird nicht unbedingt als sequentielles Array von Zeichen im Speicher gespeichert. Sie müssen beim Senden dieser HTTP-Header tatsächlich ein fortlaufendes Array von Zeichen haben, wodurch der interne Puffer möglicherweise kopiert/geändert wird, um ihn sequentiell zu machen.

std::string mit dem entsprechenden std::string::reserve hat in dieser Situation keinen Grund, langsamer als std::ostringstream zu handeln.

std::ostringstream ist jedoch wahrscheinlich schneller zum Anhängen, wenn Sie absolut keine Ahnung haben, welche Größe Sie reservieren müssen. Wenn Sie std::string verwenden und Ihre Zeichenfolge wächst, müssen Sie schließlich den gesamten Puffer neu zuordnen und kopieren. Es wäre besser, eine std::ostringstream::str() zu verwenden, um die Daten auf einmal sequenziell zu machen, verglichen mit mehreren Neuzuordnungen, die andernfalls auftreten würden.

P.S. Pre-C++ 11 std::string muss auch nicht sequenziell sein, während fast alle Bibliotheken dies als sequenziell implementieren. Sie könnten es riskieren oder stattdessen std::vector<char> verwenden. Sie müssen zum Anhängen Folgendes verwenden:

char str[] = ";charset=";
vector.insert(vector.end(), str, str + sizeof(str) - 1);

std::vector<char> ist am besten für die Leistung, da er wahrscheinlich billiger zu konstruieren ist, im Vergleich zu std::string und der tatsächlichen Konstruktionszeit jedoch wahrscheinlich nicht von Bedeutung ist. Ich habe etwas Ähnliches getan, was Sie versuchen, und bin vorher mit std::vector<char> gegangen. Rein aus logischen Gründen; vector schien besser zu passen. Sie wollen eigentlich keine String-Manipulationen oder ähnliches. Auch Benchmarks, die ich später durchführte, haben gezeigt, dass sie besser abschneiden, oder vielleicht lag es nur daran, dass ich Operationen mit std::string nicht gut genug implementierte.

Bei der Auswahl ist der Container, der Anforderungen an Ihre Anforderungen und minimale zusätzliche Funktionen erfüllt, die beste Lösung.

10
Etherealone

constructing Ein Stream-Objekt ist eine wesentlich komplexere Operation als das Erstellen eines String-Objekts, da es unter anderem sein Member std::locale enthalten muss (und daher konstruieren muss), um den Status zu erhalten (das Gebietsschema ist jedoch mit einem großer Rand am schwersten).

Das Anhängen ist ähnlich: Beide pflegen ein zusammenhängendes Array von Zeichen, beide weisen mehr zu, wenn die Kapazität überschritten wird. Die einzigen Unterschiede, die ich mir vorstellen kann, sind, dass beim Anhängen an einen Stream ein virtueller Member-Funktionsaufruf pro Überlauf vorhanden ist (zusätzlich zur Speicherzuweisung/zum Kopieren, die die Überlaufbehandlung ohnehin dominiert), und operator<< einige zusätzliche Überprüfungen des Befehls durchführt Stromzustand.

Beachten Sie auch, dass Sie str () aufrufen, wodurch der gesamte String noch einmal kopiert wird. Das Stream-Beispiel ist also mehr darauf ausgerichtet und sollte langsamer sein.

Lass uns testen:

#include <sstream>
#include <string>
#include <numeric>

volatile unsigned int sink;
std::string contentType(50, ' ');
std::string charset(50, ' ');
int main()
{
 for(long n = 0; n < 10000000; ++n)
 {
#ifdef TEST_STREAM    
    std::ostringstream os;
    os << "Content-Type: " << contentType << ";charset=" << charset << "\r\n";
    std::string header = os.str();
#endif
#ifdef TEST_STRING
    std::string header("Content-Type: ");
    header.append(contentType);
    header.append(";charset=");
    header.append(charset);
    header.append("\r\n");
#endif
    sink += std::accumulate(header.begin(), header.end(), 0);
 }
}

das sind 10 Millionen Wiederholungen

Bei meinem Linux bekomme ich

                   stream         string
g++ 4.8          7.9 seconds      4.4 seconds
clang++/libc++  11.3 seconds      3.3 seconds

für diesen Anwendungsfall scheinen Strings in diesen beiden Implementierungen jedoch schneller zu funktionieren. Offensichtlich haben beide Möglichkeiten jedoch eine Menge zu verbessern (reserve ()), die Stream-Konstruktion aus der Schleife zu verschieben und einen Stream zu verwenden, der nicht erforderlich ist Kopieren, um auf den Puffer zuzugreifen usw.)

20
Cubbi

Mit Stream können Sie Ihre Klasse Myclass die Operation << überschreiben, damit Sie schreiben können

MyClass x;
ostringstream y;
y << x;

Für das Anfügen benötigen Sie eine ToString-Methode (oder etwas Ähnliches), da Sie die Anhängefunktion von string nicht überschreiben können.

Verwenden Sie für einige Codeteile das, was Ihnen am besten gefällt. Verwenden Sie Stream für größere Projekte, bei denen es nützlich ist, ein Objekt einfach zu streamen.

1
Sorin

Wenn Sie sich Gedanken über die Geschwindigkeit machen, sollten Sie Profile erstellen und/oder testen. Theoretisch sollte std::string::append nicht langsamer sein, da es einfacher ist (Stream muss mit Gebietsschema umgehen, unterschiedliche Formatierungen verwenden und generischer sein). Wie schnell die eine oder andere Lösung wirklich ist, können Sie jedoch nur durch Testen realisieren.

0
Slava