2011-12-05 5 views
6

Mam projekt, w którym potrzebuję do odczytu/zapisu dużych plików.Specyficzne zachowanie std :: string w visual studio?

Postanowiłem użyć ifstream :: read(), aby umieścić te pliki w pamięci w jednym przebiegu, w std :: string. (który wydaje się być najszybszy sposób to zrobić w C++: http://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html i http://insanecoding.blogspot.com/2011/11/reading-in-entire-file-at-once-in-c.html)

Podczas przełączania między plikami, to wtedy trzeba „reset” na std :: string używany jako bufor pamięci poprzedniego (tj wymazać char [] buffer do wolnej pamięci)

próbowałem:

std::string::clear() 
std::string::assign("") 
std::string::erase(0, std::string::npos) 
std::string::resize(0) 
std::string::reserve(0) 

ale pod Visual Studio 2008, to nie zwalnia pamięć używaną wewnątrz std :: samego łańcucha: jego podstawowej bufor nie jest anulowane.

Jedyny sposób, w jaki go usunąłem, to wywołanie std :: string :: swap (std :: string ("")) wymuszenie zmiany buforów wewnętrznych między rzeczywistym std :: string i empty w parametrze.

znajdę ten problem nieco dziwne ...

I tylko przetestowane w Visual Studio 2008, nie wiem, czy to zachowanie STL standardzie lub jeśli to MSVC specyficzne.

Czy możesz podać mi jakąś wskazówkę?

+5

Zamiana to standardowy sposób udostępniania pojemnikom zarezerwowanej pamięci. Odczytanie pliku przy użyciu 'std :: string' jest daleko od optymalnego sposobu. –

+1

@ VladLazarenko: standardowa i możliwie najszybsza. – Nawaz

+3

Dlaczego ** miałbyś ** oczekiwać, że ktoś zwolni bufor? C++ 11 dodaje jawne 'shrink_to_fit()', aby wykonać niewiążące żądanie usunięcia. –

Odpowiedz

4

Jak komentuje Vlad i Alf, std::string().swap(the_string) jest sposobem C++ 98 na uwolnienie pojemności the_string, a the_string.shrink_to_fit() jest sposobem C++ 11.

Jeśli chodzi o powód, dla którego clear(), erase(), resize() itp. Nie rób tego, jest to optymalizacja, aby zmniejszyć alokacje, gdy używasz ciąg w kółko. Jeśli clear() uwolniłby pojemność sznurka, zazwyczaj musiałbyś ponownie przydzielić podobną ilość miejsca w następnej iteracji, co może zająć trochę czasu, aby implementacja mogła zaoszczędzić, utrzymując pojemność wokół. Ta implementacja nie jest gwarantowana przez standard, ale jest bardzo powszechna w implementacjach.

reserve() udokumentowano

Wywołanie rezerwy() z argumentem res_arg mniejszej pojemności() jest w istocie niewiążące żądanie kurczyć. Wywołanie z res_arg < = size() jest w rzeczywistości niewiążącym żądaniem dopasowania dopasowującego.

co oznacza, że ​​implementacje mają większe szanse na zwolnienie pojemności połączenia reserve(). Jeśli dobrze je przeczytam, libc++ i libstdC++ zwalniają przestrzeń, gdy wywołują reserve(0), ale jest to możliwe, aby biblioteka VC++ dokonała przeciwnego wyboru.

Edytuj: Jak mówi Penelope, zachowanie w tym przypadku jest dokładnie takie samo jak zachowanie std::vector.

+1

Chciałbym tylko dodać ... 'ciąg' zachowuje się w większości jak 'wektor' s ... i jeśli dodasz dane do 'std :: vector', gdy jego rozmiar osiągnie rezerwowaną pojemność, jego pojemność podwaja się (i nic nie musi (musi) się zdarzyć, gdy rozmiar maleje). W ten sposób czas wstawiania z tyłu wektora jest mniej więcej stały, a jednocześnie jest efektywny pod względem pamięci: rezerwacja pamięci (powolna operacja) odbywa się wykładniczo rzadziej w czasie, podczas gdy rozmiar wektora nigdy nie jest ponad dwa razy większy niż potrzebny rozmiar – penelope