2016-08-06 83 views
-4

Ich arbeite an einem C++ Projekt (mit VS2008), wo ich eine sehr große XML-Datei in std::wstring aus einer Datei laden muss. Derzeit wird die folgende Zeile reserviert Speicher, bevor die Daten geladen:Was ist der schnellste Weg, die Größe von std :: string zu ändern?

//std::wstring str; 
//size_t ncbDataSz = file size in bytes 

str.resize(ncbDataSz/sizeof(WCHAR)); 

Aber mein aktuelles Problem ist, dass die resize Methode für eine größere Stringgröße etwas lange Zeit in Anspruch nimmt (Getestet habe ich es nur mit 3 GB Daten in einem x64 Projekt, auf einem Desktop-PC mit 12GB von freiem RAM und es dauerte etwa 4-5 Sekunden zu vervollständigen.)

Also ich bin gespannt, gibt es eine schnellere (optimierte) Methode zur Größenänderung std::string? Ich frage nur nach Windows.

+3

'std :: string :: reserve' reserven,' std :: string :: resize' schreibt auch in den speicher ... was du willst überschreiben mittelbar, nehme ich an. – LogicStuff

+0

Möchten Sie die Größe ändern oder reservieren? – user463035818

+0

@LogicStuff: 'reserve' ist ein seltsames Biest. Es "reserviert" den Speicher, aber man kann nicht direkt darauf als zusammenhängendes Byte-Array zugreifen, richtig? Ich muss 'append' darauf ansprechen. In diesem Fall ist es für mich nutzlos für diese Typoptimierung. – c00000fd

Antwort

1

Anstatt die Eingabezeichenfolge zu ändern, können Sie sie einfach unter Verwendung von std::string::reserve zuweisen, da die Größenänderung auch jedes Element initialisiert.

Man könnte so etwas wie dies zu sehen, ob es die Leistung für Sie verbessert:

std::wstring load_file(std::string const& filename) 
{ 
    std::wifstream ifs(filename, std::ios::ate); 

    // errno works on POSIX systems not sure about windows 
    if(!ifs) 
     throw std::runtime_error(std::strerror(errno)); 

    std::wstring s; 
    s.reserve(ifs.tellg()); // allocate but don't initialize 
    ifs.seekg(0); 

    wchar_t buf[4096]; 
    while(ifs.read(buf, sizeof(buf)/sizeof(buf[0]))) 
     s.append(buf, buf + ifs.gcount()); // this will never reallocate 

    return s; 
} 
+0

Danke. Aber was Sie tun, ist, dass Sie zwei Puffer vorreservieren: 's.reserve' und' wchar_t buf' und ich versuche, mit nur einem davon durchzukommen. Also, nachdem ich 's.reserve' habe, wie kann ich direkt in es laden? Oder 'ReadFile (hFile, & s [0], sz, szRead, NULL);' Ich muss die Größe anpassen, richtig. Aber wie? – c00000fd

+0

@ c00000fd Sie können nicht in den reservierten Speicher einlesen. Allerdings ist die Zuweisung für 'buf [4096]' auf dem Stapel, der blitzschnell ist (eine Anweisung?). Am Ende des Tages kann nur die Messung sagen, ob es schneller ist oder nicht. – Galik

+0

Ich spreche über GB Daten, so Stack ist nicht in Frage. Und wenn man es in kleine Stücke von einer Datei lädt, verlangsamt es das sogar noch mehr, als wenn ich nicht 'resize' verwende. – c00000fd

1

instanziiert mit char_traits basic_string die nichts auf assign tut (Anzahl):

#include <string> 

struct noinit_char_traits : std::char_traits<char> { 
    using std::char_traits<char>::assign; 
    static char_type* assign(char_type* p, std::size_t count, char_type a) { return p; } 
}; 

using noinit_string = std::basic_string<char, noinit_char_traits>; 

Beachten Sie, dass es wirkt sich auch auf Funktionen wie basic_string :: fill() usw. aus.