22,1 — std::string i std::wstring

Biblioteka standardowa zawiera wiele przydatnych klas - ale być może najbardziej użyteczną jest std::string. std::string (i std::wstring) to klasa łańcuchów, która udostępnia wiele operacji przypisywania, porównywania i modyfikowania ciągów. W tym rozdziale przyjrzymy się szczegółowo tym klasom ciągów.

Uwaga: Ciągi w stylu C będą nazywane „ciągami w stylu C”, podczas gdy std::string (i std::wstring) będą nazywane po prostu „łańcuchami”.

Nota autora

Ten rozdział jest nieco przestarzały i prawdopodobnie zostanie skondensowany w przyszłej aktualizacji. Możesz przeglądać materiał w poszukiwaniu pomysłów i przydatnych przykładów, ale w celu uzyskania najbardziej aktualnych informacji należy preferować strony z odniesieniami technicznymi (np. cppreference).

Motywacja dla klasy string

W poprzedniej lekcji omówiliśmy Ciągów w stylu C, który wykorzystuje tablice char do przechowywania ciągu znaków. Jeśli próbowałeś zrobić cokolwiek z ciągami w stylu C, bardzo szybko dojdziesz do wniosku, że praca z nimi jest uciążliwa, łatwo je zepsuć i trudno debugować.

Łańcuchy w stylu C mają wiele wad, związanych przede wszystkim z faktem, że musisz sam zarządzać całą pamięcią. Na przykład, jeśli chcesz przypisać ciąg „witaj!” do bufora, musisz najpierw dynamicznie przydzielić bufor o odpowiedniej długości:

char* strHello { new char[7] };

Nie zapomnij uwzględnić dodatkowego znaku dla terminatora zerowego!

Następnie musisz faktycznie skopiować wartość do:

strcpy(strHello, "hello!");

Mam nadzieję, że bufor jest wystarczająco duży, aby nie doszło do przepełnienia bufora!

I oczywiście, ponieważ ciąg znaków jest przydzielany dynamicznie, musisz to zrobić pamiętaj o prawidłowym zwolnieniu alokacji, gdy już skończysz:

delete[] strHello;

Nie zapomnij użyć usuwania tablicy zamiast normalnego usuwania!

Co więcej, wiele intuicyjnych operatorów dostępnych w C do pracy z liczbami, takich jak przypisanie i porównania, po prostu nie działa z ciągami w stylu C. Czasami wydaje się, że działają, ale w rzeczywistości dają nieprawidłowe wyniki — na przykład porównanie dwóch ciągów w stylu C za pomocą == w rzeczywistości spowoduje porównanie wskaźników, a nie porównanie ciągów. Przypisanie jednego ciągu w stylu C do innego za pomocą operator= będzie początkowo działać, ale w rzeczywistości powoduje wykonanie kopii wskaźnika (płytka kopia), co generalnie nie jest tym, czego chcesz. Tego typu rzeczy mogą prowadzić do awarii programów, które są bardzo trudne do znalezienia i debugowania!

Konkluzja jest taka, że praca z ciągami znaków w stylu C wymaga zapamiętania wielu drobiazgowych zasad dotyczących tego, co jest bezpieczne/niebezpieczne, zapamiętywania kilku funkcji o śmiesznych nazwach, takich jak strcat() i strcmp() zamiast używania intuicyjnych operatorów, a także wykonywania wielu ręcznych operacji zarządzania pamięcią.

Na szczęście C++ i standardowa biblioteka zapewniają znacznie lepszy sposób radzenia sobie z ciągami znaków: klasy std::string i std::wstring. Wykorzystując pojęcia C++, takie jak konstruktory, destruktory i przeciążanie operatorów, std::string umożliwia tworzenie ciągów znaków i manipulowanie nimi w intuicyjny i bezpieczny sposób! Koniec z zarządzaniem pamięcią, koniec z dziwnymi nazwami funkcji i znacznie zmniejszone ryzyko katastrofy.

Zarejestruj się!

Przegląd ciągów znaków

Wszystkie funkcje ciągów w standardowej bibliotece znajdują się w pliku nagłówkowym. Aby z niego skorzystać, po prostu dołącz nagłówek ciągu:

    #include <string>

W nagłówku ciągu znajdują się właściwie 3 różne klasy ciągów. Pierwsza to szablonowa klasa bazowa o nazwie basic_string<>:

namespace std
{
    template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
        class basic_string;
}

Nie będziesz pracować z tą klasą bezpośrednio, więc nie martw się na razie o cechy lub alokator. Wartości domyślne wystarczą w prawie każdym możliwym przypadku.

Istnieją dwie wersje basic_string<> dostarczane przez standardową bibliotekę:

namespace std
{
    typedef basic_string<char> string;
    typedef basic_string<wchar_t> wstring;
}

To są dwie klasy, których będziesz faktycznie używać. std::string jest używany dla standardowych ciągów znaków ascii i utf-8. std::wstring jest używany do ciągów znaków dwuznakowych/unicode (utf-16). Nie ma wbudowanej klasy dla ciągów utf-32 (chociaż powinieneś móc rozszerzyć własną z basic_string<>, jeśli jej potrzebujesz).

Chociaż będziesz bezpośrednio używać std::string i std::wstring, cała funkcjonalność ciągów jest zaimplementowana w klasie basic_string<>. String i wstring mają bezpośredni dostęp do tej funkcjonalności dzięki szablonowi. W związku z tym wszystkie przedstawione funkcje będą działać zarówno dla stringów, jak i wstringów. Jednakże, ponieważ basic_string jest klasą szablonową, oznacza to również, że kompilator będzie generował okropnie wyglądające błędy szablonu, gdy zrobisz coś niepoprawnego składniowo z ciągiem znaków lub wstringiem. Nie daj się zastraszyć tymi błędami; wyglądają znacznie gorzej niż są w rzeczywistości!

Oto lista wszystkich funkcji w klasie string. Większość tych funkcji ma wiele odmian do obsługi różnych typów danych wejściowych, które omówimy bardziej szczegółowo w następnych lekcjach.

FunkcjaEfekt
Tworzenie i niszczenie
(konstruktor)
(destruktor)
Utwórz lub skopiuj ciąg znaków
Zniszcz ciąg
Rozmiar i pojemność
capacity()
empty()
length(), size()
max_size()
reserve()
Zwraca liczbę znaków, które mogą być przechowywane bez realokacji
Zwraca wartość logiczną wskazującą, czy ciąg znaków jest pusty
Zwraca liczbę znaków w ciągu
Zwraca maksymalny rozmiar łańcucha, który można przydzielić
Zwiększ lub zmniejsz pojemność ciągu
Dostęp do elementu
[], at()Dostęp do znaku w określonym miejscu indeks
Modyfikacja
=, przypisanie()
+=, append(), push_back()
insert()
clear()
erase()
replace()
resize()
swap()
Przypisuje nową wartość do ciągu
Łączy znaki koniec ciągu
Wstawia znaki pod dowolnym indeksem w ciągu
Usuń wszystkie znaki w ciągu
Usuń znaki pod dowolnym indeksem w ciągu
Zamień znaki o dowolnym indeksie na inne znaki
Rozwiń lub zmniejsz ciąg (obcina lub dodaje znaki na końcu string)
Zamiana wartości dwóch ciągów znaków
Input i Output
>>, getline()
<<
c_str()
copy()
data()
Odczytuje wartości ze strumienia wejściowego do string
Zapisuje wartość ciągu do strumienia wyjściowego
Zwraca zawartość łańcucha w postaci łańcucha w stylu C zakończonego znakiem NULL
Kopiuje zawartość (niezakończoną znakiem NULL) do tablicy znaków
Tak samo jak c_str(). Przeciążenie inne niż const umożliwia zapis do zwróconego ciągu.
Porównanie ciągów
==, !=
<, <=, > >=
compare()
Porównuje, czy dwa ciągi są równe/nierówne (zwraca wartość bool)
Porównuje, czy dwa ciągi są mniejsze/większe od siebie (zwraca wartość bool)
Porównuje, czy dwa ciągi są równe/nierówne (zwraca -1, 0 lub 1)
Podciągi i łączenie
+
substr()
Łączy dwa ciągi znaków
Zwraca podciąg
Wyszukiwanie
find()
find_first_of()
find_first_ not_of()
find_last_of()
find_last_not_of()
rfind()
Znajdź indeks pierwszego znaku/podciągu
Znajdź indeks pierwszego znaku ze zbioru znaków
Znajdź indeks pierwszego znaku nie ze zbioru znaków
Znajdź indeks ostatniego znaku ze zbioru znaków
Znajdź indeks ostatniego znaku nie ze zbioru znaków
Znajdź indeks ostatniego znaku znak/podciąg

Obsługa iteratorów i alokatorów
begin(), end()
get_allocator()
rbegin(), rend()
Obsługa iteratora w kierunku do przodu dla początku/końca łańcucha
Zwraca alokator
Obsługa iteratora w odwrotnym kierunku dla początku/końca łańcucha string

Chociaż standardowe klasy ciągów bibliotecznych zapewniają dużą funkcjonalność, istnieje kilka godnych uwagi pominięć:

  • Konstruktory do tworzenia ciągów znaków z liczb
  • Funkcje wielkich/wielkich/małych liter
  • Porównania bez uwzględniania wielkości liter
  • Tokenizacja / dzielenie ciągu na tablicę
  • Łatwe funkcje uzyskiwania lewa lub prawa część ciągu
  • Przycinanie białych znaków
  • Formatowanie łańcucha w stylu sprintf
  • Konwersja z utf-8 na utf-16 lub odwrotnie

W przypadku większości z nich będziesz musiał albo napisać własne funkcje, albo przekonwertować ciąg na ciąg w stylu C (przy użyciu c_str()) i skorzystać z funkcji C, które oferują tę funkcjonalność.

W następnych lekcjach przyjrzymy się bardziej szczegółowo różnym funkcjom klasy string. Chociaż w naszych przykładach będziemy używać stringów, wszystko ma również zastosowanie do wstring.

guest
Twój adres e-mail nie zostanie wyświetlony
Znalazłeś błąd? Zostaw komentarz powyżej!
Komentarze związane z poprawkami zostaną usunięte po przetworzeniu, aby pomóc zmniejszyć bałagan. Dziękujemy za pomoc w ulepszaniu witryny dla wszystkich!
Awatary z https://gravatar.com/ są połączone z podanym adresem e-mail.
Powiadamiaj mnie o odpowiedziach:  
107 Komentarze
Najnowsze
Najstarsze Najczęściej głosowane
Wbudowane opinie
Wyświetl wszystkie komentarze