2015-12-30 25 views
6

Mam unordered_set o znakachEfektywna konstrukcja std :: string z std :: unordered_set <char>

std::unordered_set<char> u_setAlphabet; 

Następnie chcę, aby uzyskać zawartość z zestawu jako std :: string. Moja implementacja wygląda teraz tak:

std::string getAlphabet() { 
    std::string strAlphabet; 
    for (const char& character : u_setAlphabet) 
     strAlphabet += character; 
    return strAlphabet; 
} 

Czy to dobry sposób na rozwiązanie tego zadania? Dodatki znaków-znaków do łańcucha wydają się nie być optymalne dla dużych u_setAlphabet (multiple reallocs?). Czy jest jakaś inna metoda?

+1

Co do etykiety: identyfikator w minimalnym, reprezentatywnym przykładowym kodzie powinien prawdopodobnie nie być niewygodny jak "u_setAlphabet". Dobrymi identyfikatorami na przykład kodu są 'foo',' bar' i 'x'. –

+1

@KerrekSB Z drugiej strony, muszę powiedzieć, że wolę kod, który kopiuje nieuporządkowany set 'setAlphabet' na ciąg' strAlphabet' do tego, który kopiuje zestaw (lub był ciągiem?) 'Foo' na ciąg (czy był ustawiony? ?) 'bar'. – Angew

+0

@KerrekSB dobry punkt, mam na uwadze twoje zalecenie na następne pytanie. Niektóre odpowiedzi używają teraz tych nazw, więc nie zmienię treści pytania tutaj – saleph

Odpowiedz

12

Odpowiedź najprostsza, najbardziej czytelny i najbardziej efektywny jest:

return std:string(s.begin(), s.end()); 

Implementacja może wybrać, aby wykrywać długość zakresie up-przedniej i przydzielić tylko raz; zarówno libC++, jak i libstdC++ robią to, gdy mają określony zakres iteratora.

Klasa string oferuje również reserve, podobnie jak vector, zarządzać pojemność:

std::string result 
result.reserve(s.size()); 
for (unsigned char c : s) result.push_back(c); // or std::copy 
return result; 

Oferuje również assign, append i insert funkcji składowych, ale ponieważ te dają silną gwarancję wyjątku, mogą one musicie przydzielić nowy bufor przed zniszczeniem starego (dzięki @TC za wskazanie tego kluczowego szczegółu!). Implementacja libC++ nie rozdziela, jeśli istniejąca pojemność jest wystarczająca, podczas gdy implementacja libstdC++ GCC5 przenosi się bezwarunkowo.

+0

ouh, rezerwy, o tym zapomniałem :) Ale czy konstruktor std :: string nie optymalizuje go sam? – saleph

+2

Chciałbym polecić kod 'reserve()' tylko wtedy, gdy wiesz, że naprawdę potrzebujesz kodu krytycznego dla wydajności i zauważyłeś różnicę mierząc go. To zakłóca twój kod, ale jeśli wzmocnienie to usprawiedliwia, jest w porządku. Dobra standardowa implementacja biblioteki zarezerwuje pamięć tylko raz, nawet jeśli konstruktor bierze iteratory. Jedynym koszmarem, jaki otrzymasz, jest przejście do znalezienia rozmiaru z przodu. –

+3

@Saleph Nie, ponieważ 'std :: set :: iterator' spełnia tylko dwukierunkowyIterator' std :: distance' jest zatem operacją O (N). Jednakże, 'std :: set :: size' jest operacją o stałym czasie. – Daniel

12

std::string ma a constructor na to:

auto s = std::string(begin(u_setAlphabet), end(u_setAlphabet)); 
10

Lepiej jest użyć konstruktora że acepts iteratory. Na przykład

std::string getAlphabet() { 
    return { u_setAlphabet.begin(), u_setAlphabet.end() }; 
} 
+0

to dużo w stylu C++ 11 :) Ale co sądzisz (według ciebie) o rozróżnialności czytelności między twoim a @xtofl awer? Racja - twoja implementacja jest najkrótsza, ale na pierwszy rzut oka wygląda jakaś magia :) – saleph

+1

@saleph Jeśli C++ wygląda jak magia, powinieneś nauczyć się C++ :) Jeśli chodzi o porównanie to 1) odpowiedź xtofl jest również napisany przy użyciu funkcji C++ 11 i 2) nie odpowiada pytaniu, gdzie mówi się o definicji funkcji. –

+0

Oczywiście rozumiem twój kod :) Ale czy twoja implementacja nie jest podobna do tej z @KerrecSB? Konstruuje ciąg znaków, który z pewnością zostanie przeniesiony później (np. 'Std :: string foo (getAlphabet());') – saleph

1

Zarówno i są takie same w C++ 11. Preferuję rozwiązanie @VladfromMoscow, ponieważ nie musimy przyjmować żadnych założeń dotyczących zwróconego typu obiektu tymczasowego.

+0

ale czy ta ukryta konstrukcja nie jest mniej oczywista, według Pana? Jestem naprawdę początkującym w C++, więc mój sens czytelności nie jest bardzo doświadczony :) – saleph

Powiązane problemy