22.1 — std::string and std::wstring
The standard library contains many useful classes — but perhaps the most useful is std::string. std::string (and std::wstring) is a string class that provides many operations to assign, compare, and modify strings. In this chapter, we’ll look into these string classes in depth.
Note: C-style strings will be referred to as “C-style strings”, whereas std::string (and std::wstring) will be referred to simply as “strings”.
This chapter is somewhat outdated and will likely be condensed in a future update. Feel free to scan the material for ideas and useful examples, but technical reference sites (e.g. cppreference) should be preferred for the most up-to-date information.
Motivation for a string class
In a previous lesson, we covered C-style strings, which uses char arrays to store a string of characters. If you’ve tried to do anything with C-style strings, you’ll very quickly come to the conclusion that they are a pain to work with, easy to mess up, and hard to debug.
C-style strings have many shortcomings, primarily revolving around the fact that you have to do all the memory management yourself. For example, if you want to assign the string “hello!” into a buffer, you have to first dynamically allocate a buffer of the correct length:
Don’t forget to account for an extra character for the null terminator!
Then you have to actually copy the value in:
Hopefully you made your buffer large enough so there’s no buffer overflow!
And of course, because the string is dynamically allocated, you have to remember to deallocate it properly when you’re done with it:
Don’t forget to use array delete instead of normal delete!
Furthermore, many of the intuitive operators that C provides to work with numbers, such as assignment and comparisons, simply don’t work with C-style strings. Sometimes these will appear to work but actually produce incorrect results — for example, comparing two C-style strings using == will actually do a pointer comparison, not a string comparison. Assigning one C-style string to another using operator= will appear to work at first, but is actually doing a pointer copy (shallow copy), which is not generally what you want. These kinds of things can lead to program crashes that are very hard to find and debug!
The bottom line is that working with C-style strings requires remembering a lot of nit-picky rules about what is safe/unsafe, memorizing a bunch of functions that have funny names like strcat() and strcmp() instead of using intuitive operators, and doing lots of manual memory management.
Fortunately, C++ and the standard library provide a much better way to deal with strings: the std::string and std::wstring classes. By making use of C++ concepts such as constructors, destructors, and operator overloading, std::string allows you to create and manipulate strings in an intuitive and safe manner! No more memory management, no more weird function names, and a much reduced potential for disaster.
String overview
All string functionality in the standard library lives in the header file. To use it, simply include the string header:
There are actually 3 different string classes in the string header. The first is a templated base class named basic_string<>:
You won’t be working with this class directly, so don’t worry about what traits or an Allocator is for the time being. The default values will suffice in almost every imaginable case.
There are two flavors of basic_string<> provided by the standard library:
These are the two classes that you will actually use. std::string is used for standard ascii and utf-8 strings. std::wstring is used for wide-character/unicode (utf-16) strings. There is no built-in class for utf-32 strings (though you should be able to extend your own from basic_string<> if you need one).
Although you will directly use std::string and std::wstring, all of the string functionality is implemented in the basic_string<> class. String and wstring are able to access that functionality directly by virtue of being templated. Consequently, all of the functions presented will work for both string and wstring. However, because basic_string is a templated class, it also means the compiler will produce horrible looking template errors when you do something syntactically incorrect with a string or wstring. Don’t be intimidated by these errors; they look far worse than they are!
Here’s a list of all the functions in the string class. Most of these functions have multiple flavors to handle different types of inputs, which we will cover in more depth in the next lessons.
- Regular expression support
- Constructors for creating strings from numbers
- Capitalization / upper case / lower case functions
- Case-insensitive comparisons
- Tokenization / splitting string into array
- Easy functions for getting the left or right hand portion of string
- Whitespace trimming
- Formatting a string sprintf style
- Conversion from utf-8 to utf-16 or vice-versa
For most of these, you will have to either write your own functions, or convert your string to a C-style string (using c_str()) and use the C functions that offer this functionality.
In the next lessons, we will look at the various functions of the string class in more depth. Although we will use string for our examples, everything is equally applicable to wstring.
Классы string и wstring. Часть 5
Класс string стандартной библиотеки C++ хорошо известен и охотно используем. Но не все и не всегда задумываются над тем, что класс string , при некоторых отличиях в деталях — это и есть контейнер вектор: vector < char > . Правда, он дополнен некоторыми особенностями (но такой код и вы сами могли бы написать):
Метод size() задублирован методом length(). Они полностью тождественны, из соображений удобства. Просто для строки естественнее иметь длину, чем размер;
Определены перегруженные операции + , += которые возвращают конкатенацию (объединение) строк;
Определён конструктор, инициализирующий string при создании начальным значением символьной строки в формате ASCIIZ ( char* — указатель на символьный массив в стиле C завершающийся нулём);
Определён метод c_str() , который возвращает указатель на внутреннее содержимое строки в формате ASCIIZ. Поскольку это внутреннее значение, его можно использовать, но не стоит пытаться его изменять. Это хорошо не закончится.
Во всём же остальном строки ведут себя точно как вектор, и к ним применимы все операции над векторами. Понимание того, что представляет собой класс string ( vector<char> ) может позволить создать ряд неожиданных эффектов. Например, поскольку нулевой символ не имеет для vector<char> никакого особого значения (в отличие от строки C), то его тоже вполне можно «заталкивать» в конец string. Тем самым можно поместить в единственную переменную string целый массив C-строк или даже целый текст.
Вот, как подобным образом поместить весь набор переменных окружения ( environment ) операционной системы в одну переменную string :
Урок №200. Строковые классы std::string и std::wstring
Стандартная библиотека C++ содержит много полезных классов, но одним из наиболее полезных является std::string. std::string (и std::wstring) — это строковый класс, который позволяет выполнять операции присваивания, сравнения и изменения строк. На следующих нескольких уроках мы подробно рассмотрим строковые классы Стандартной библиотеки С++.
Примечание: Строки C-style обычно называют «строками C-style», тогда как std::string (и std::wstring) обычно называют просто «строками».
Зачем нужен std::string?
Мы уже знаем, что строки C-style используют массивы типа char для хранения целой строки. Если вы попытаетесь что-либо сделать со строками C-style, то вы очень быстро обнаружите, что работать с ними трудно, запутаться легко, а проводить отладку сложно.
Строки C-style имеют много недостатков, в первую очередь связанных с тем, что вы должны самостоятельно управлять памятью. Например, если вы захотите поместить строку Hello! в буфер, то вам сначала нужно будет динамически выделить буфер правильной длины:
Не забудьте учесть дополнительный символ для нуль-терминатора! Затем вам нужно будет скопировать значение:
И здесь вам нельзя прогадать с длиной буфера, иначе произойдет переполнение! И, конечно, поскольку строка выделяется динамически, то вы должны её еще и правильно удалить:
Не забудьте использовать форму оператора delete, которая работает с массивами, а не обычную форму оператора delete.
Кроме того, многие из интуитивно понятных операторов, которые предоставляет язык C++ для работы с числами, такие как = , == , != , < , > , >= и <= попросту не работают со строками C-style. Иногда они могут работать без ошибок со стороны компилятора, но результат будет неверным. Например, сравнение двух строк C-style с использованием оператора == на самом деле выполнит сравнение указателей, а не строк. Присваивание одной строки C-style другой строке C-style с использованием оператора = будет работать, но выполняться будет копирование указателя (поверхностное копирование), что не всегда то, что нам нужно. Такие вещи могут легко привести к ошибкам и сбоям в программе, а разбираться с ними не так уж и легко (относительно)!
Суть в том, что работая со строками C-style, вам нужно помнить множество придирчивых правил о том, что делать безопасно, а что — нет; запоминать много функций, таких как strcat() и strcmp(), чтобы использовать их вместо интуитивных операторов; а также самостоятельно выполнять управление памятью.
К счастью, язык C++ предоставляет гораздо лучший способ для работы со строками: классы std::string и std::wstring. Используя такие концепции С++, как конструкторы, деструкторы и перегрузку операторов, std::string позволяет создавать и манипулировать строками в интуитивно понятной форме и, что не менее важно, выполнять это безопасно! Никакого управления памятью, запоминания странных названий функций и значительно меньшая вероятность возникновения ошибок/сбоев.
Класс std::string
Весь функционал класса std::string находится в заголовочном файле string:
std:: wstring
This is an instantiation of the basic_string class template that uses wchar_t as the character type, with its default char_traits and allocator types (see basic_string for more info on the template).
Member types
| member type | definition |
|---|---|
| value_type | wchar_t |
| traits_type | char_traits<wchar_t> |
| allocator_type | allocator<wchar_t> |
| reference | wchar_t& |
| const_reference | const wchar_t& |
| pointer | wchar_t* |
| const_pointer | const wchar_t* |
| iterator | a random access iterator to wchar_t (convertible to const_iterator) |
| const_iterator | a random access iterator to const wchar_t |
| reverse_iterator | reverse_iterator<iterator> |
| const_reverse_iterator | reverse_iterator<const_iterator> |
| difference_type | ptrdiff_t |
| size_type | size_t |
Member functions
Note: The references to the members of its basic template (basic_string) are linked here.
(constructor) Construct basic_string object (public member function ) (destructor) String destructor (public member function ) operator= String assignment (public member function )
Iterators:
begin Return iterator to beginning (public member function ) end Return iterator to end (public member function ) rbegin Return reverse iterator to reverse beginning (public member function ) rend Return reverse iterator to reverse end (public member function ) cbegin Return const_iterator to beginning (public member function ) cend Return const_iterator to end (public member function ) crbegin Return const_reverse_iterator to reverse beginning (public member function ) crend Return const_reverse_iterator to reverse end (public member function )
Capacity:
size Return size (public member function ) length Return length of string (public member function ) max_size Return maximum size (public member function ) resize Resize string (public member function ) capacity Return size of allocated storage (public member function ) reserve Request a change in capacity (public member function ) clear Clear string (public member function ) empty Test whether string is empty (public member function ) shrink_to_fit Shrink to fit (public member function )
Element access:
operator[] Get character of string (public member function ) at Get character of string (public member function ) back Access last character (public member function ) front Access first character (public member function )
Modifiers:
operator+= Append to string (public member function ) append Append to string (public member function ) push_back Append character to string (public member function ) assign Assign content to string (public member function ) insert Insert into string (public member function ) erase Erase characters from string (public member function ) replace Replace portion of string (public member function ) swap Swap string values (public member function ) pop_back Delete last character (public member function )
String operations:
c_str Get C-string equivalent data Get string data (public member function ) get_allocator Get allocator (public member function ) copy Copy sequence of characters from string (public member function ) find Find first occurrence in string (public member function ) rfind Find last occurrence in string (public member function ) find_first_of Find character in string (public member function ) find_last_of Find character in string from the end (public member function ) find_first_not_of Find non-matching character in string (public member function ) find_last_not_of Find non-matching character in string from the end (public member function ) substr Generate substring (public member function ) compare Compare strings (public member function )