Czy istnieje klasa C ++ Standard Template Library, która zapewnia wydajne funkcje konkatenacji ciągów, podobny do C # 's StringBuilder lub Java StringBuffer ?
c++
stl
string-concatenation
Andrzej
źródło
źródło
std::ostringstream
.Odpowiedzi:
UWAGA, na tę odpowiedź ostatnio zwrócono uwagę. Nie zalecam tego jako rozwiązania (jest to rozwiązanie, które widziałem w przeszłości, przed STL). Jest to ciekawe podejście i powinien być stosowany wyłącznie przez
std::string
lubstd::stringstream
jeśli po profilowania kodu można odkryć to sprawia poprawę.I normalnie używać albo
std::string
albostd::stringstream
. Nigdy nie miałem z tym żadnych problemów. Zazwyczaj najpierw rezerwuję trochę miejsca, jeśli z góry znam przybliżony rozmiar struny.W odległej przeszłości widziałem innych ludzi tworzących własny zoptymalizowany konstruktor strun.
Wykorzystuje dwa łańcuchy, jeden dla większości łańcucha, a drugi jako obszar rysowania do łączenia krótkich łańcuchów. Optymalizuje dołączanie przez grupowanie krótkich operacji dołączania w jednym małym ciągu, a następnie dołączanie go do łańcucha głównego, zmniejszając w ten sposób liczbę wymaganych przesunięć w łańcuchu głównym, gdy staje się on większy.
Nie wymagałem tej sztuczki z
std::string
lubstd::stringstream
. Myślę, że był używany z zewnętrzną biblioteką ciągów przed std :: string, to było tak dawno temu. Jeśli zastosujesz strategię taką jak ten profil, najpierw zastosuj aplikację.źródło
scratch
struna naprawdę coś tutaj osiągnęła. Liczba realokacji głównego ciągu będzie w dużej mierze funkcją jego ostatecznego rozmiaru, a nie liczby operacji dołączania, chyba żestring
implementacja jest naprawdę słaba (tzn. Nie wykorzystuje wzrostu wykładniczego). Tak więc „grupowanie”append
nie pomaga, ponieważ gdy bazastring
będzie duża, będzie rosła tylko od czasu do czasu. Ponadto dodaje kilka zbędnych operacji kopiowania i może powodować więcej realokacji (stąd wywołania donew
/delete
), ponieważ dodajesz do krótkiego ciągu.str.reserve(1024);
, że byłoby szybsze niż toSposobem C ++ byłoby użycie std :: stringstream lub po prostu zwykłego łączenia ciągów. Ciągi w języku C ++ są zmienne, więc względy wydajności dotyczące konkatenacji są mniej ważne.
jeśli chodzi o formatowanie, możesz wykonać to samo formatowanie w strumieniu, ale w inny sposób, podobny do
cout
. lub możesz użyć silnie typowanego funktora, który to ujmuje i dostarcza String.Format podobny do interfejsu, np. boost :: formatźródło
StringBuilder
istnieje, aby pokryć nieefektywność niezmiennego podstawowego typu String Javy . Innymi słowyStringBuilder
to patchwork, więc powinniśmy się cieszyć, że nie potrzebujemy takiej klasy w C ++.O(n)
ogólnie.Ta
std::string.append
funkcja nie jest dobrą opcją, ponieważ nie akceptuje wielu form danych. Bardziej użyteczną alternatywą jest użyciestd::stringstream
; tak:źródło
std::string
jest odpowiednikiem C ++: można go modyfikować.źródło
Możesz użyć .append () do prostego łączenia łańcuchów.
Myślę, że możesz nawet zrobić:
Jeśli chodzi o operacje formatowania C #
StringBuilder
, uważamsnprintf
(lubsprintf
jeśli chcesz zaryzykować zapisanie błędnego kodu ;-)) w tablicy znaków i przekonwertować z powrotem na ciąg znaków, jest jedyną opcją.źródło
Ponieważ
std::string
w C ++ można modyfikować, możesz tego użyć. Ma funkcję+= operator
iappend
.Jeśli chcesz dołączyć dane liczbowe, skorzystaj z
std::to_string
funkcji.Jeśli chcesz jeszcze większej elastyczności w postaci możliwości szeregowania dowolnego obiektu na łańcuch, skorzystaj z
std::stringstream
klasy. Musisz jednak wdrożyć własne funkcje operatora przesyłania strumieniowego, aby działało ono z własnymi klasami niestandardowymi.źródło
std :: string's + = nie działa z const char * (czymś takim jak „string to add” wydaje się być), więc zdecydowanie użycie stringstream jest najbliższe wymaganiom - wystarczy użyć << zamiast +
źródło
Wygodny konstruktor napisów dla c ++
Jak wiele osób odpowiedziało wcześniej, std :: stringstream jest metodą z wyboru. Działa dobrze i ma wiele opcji konwersji i formatowania. IMO ma jednak jedną niedogodną wadę: nie można jej używać jako jednej linijki ani jako wyrażenia. Zawsze musisz napisać:
co jest dość denerwujące, szczególnie gdy chcesz zainicjować ciągi znaków w konstruktorze.
Powodem jest to, że a) std :: stringstream nie ma operatora konwersji na std :: string oraz b) operator << () łańcucha string nie zwraca referencji stringstream, ale referencję std :: ostream - które nie mogą być dalej obliczane jako strumień ciągów.
Rozwiązaniem jest zastąpienie std :: stringstream i lepsze dopasowanie operatorów:
Dzięki temu możesz pisać takie rzeczy
nawet w konstruktorze.
Muszę wyznać, że nie zmierzyłem wydajności, ponieważ nie korzystałem z niej w środowisku, które często korzysta z budowania ciągów, ale zakładam, że nie będzie to znacznie gorsze niż std :: stringstream, ponieważ wszystko jest zrobione poprzez referencje (oprócz konwersji na ciąg, ale to także operacja kopiowania w std :: stringstream)
źródło
std::stringstream
tak się nie zachowuje.Rope pojemnik może być wart, jeśli trzeba wstawić / Usuń ciąg na losowym miejscu docelowym lub na ciąg długich sekwencji Char. Oto przykład z implementacji SGI:
źródło
Chciałem dodać coś nowego z następujących powodów:
Za pierwszym razem nie udało mi się pokonać
std::ostringstream
„soperator<<
wydajność, ale przy większej liczbie prób udało mi się stworzyć StringBuilder, który w niektórych przypadkach jest szybszy.
Za każdym razem, gdy dołączam ciąg, po prostu przechowuję gdzieś odniesienie i zwiększam licznik całkowitego rozmiaru.
Prawdziwym sposobem, w jaki w końcu go zaimplementowałem (Horror!) Jest użycie nieprzezroczystego bufora (std :: vector <char>):
dla bajtu []
dla przeniesionych ciągów (ciągi dołączone z
std::move
)std::string
obiektu (mamy własność)na struny
std::string
obiektu (bez prawa własności)Jest jeszcze jedna drobna optymalizacja, jeśli ostatni wstawiony ciąg został przeniesiony, sprawdza wolne zarezerwowane, ale nieużywane bajty i zapisuje tam kolejne bajty zamiast używać nieprzezroczystego bufora (ma to na celu zaoszczędzenie pamięci, w rzeczywistości powoduje to, że jest nieco wolniejsza , może zależy również od procesora, a mimo to rzadko widuje się ciągi znaków z dodatkową zarezerwowaną przestrzenią)
To było w końcu nieco szybsze niż,
std::ostringstream
ale ma kilka wad:ostringstream
wniosek? posługiwać się
std::ostringstream
Naprawiono już największe wąskie gardło, a zdobywanie kilku procent punktów w szybszym tempie dzięki wdrożeniu kopalni nie jest warte wad.
źródło