C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц
Шрифт:
Интервал:
Благодаря выходу C++11 теперь даже не нужно копировать строки, когда мы хотим передать право собственности какой-то другой функции или структуре данных, поскольку можем перемещать их. Таким образом, в подобных случаях не возникает больших издержек.
По мере выхода новых стандартов класс std::string получил несколько новых свойств. Совершенно новой особенностью С++17 является std::string_view. Мы немного поработаем с ней (но впереди будет и другой пример, в котором более подробно рассматривается std::string_view), чтобы понять, как взаимодействовать с подобным инструментарием в эпоху С++17.
Как это делается
В этом примере мы создадим строки и строковые представления, а затем выполним простые операции конкатенации и преобразования.
1. Как и обычно, сначала включим заголовочные файлы и объявим об использовании пространства имен std:
#include <iostream>
#include <string>
#include <string_view>
#include <sstream>
#include <algorithm>
using namespace std;
2. Сначала создадим объекты строк. Самым очевидным способом является инстанцирование объекта класса string. Мы контролируем его содержимое, передавая конструктору строку в стиле C (которая после компиляции будет встроена в бинарный файл как статический массив, содержащий символы). Конструктор скопирует ее и сделает содержимым объекта строки a. Помимо этого, вместо инициализации строки с помощью строки в стиле C можно применить оператор строкового литерала ""s. Он создает объект строк динамически. Мы используем его для создания объекта b, что позволит применять автоматическое выведение типа.
int main()
{
string a { "a" };
auto b ( "b"s );
3. Строки, которые мы только что создали, копируют их входные данные из аргумента конструктора в собственный буфер. Чтобы не копировать строку, а просто сослаться на нее, можно воспользоваться объектами типа string_ view. Этот класс также имеет оператор литерала, он вызывается с помощью конструкции ""sv:
string_view c { "c" };
auto d ( "d"sv );
4. Теперь поработаем с нашими строками и строковыми представлениями. Для обоих типов существует перегруженная версия оператора << для класса std::ostream, поэтому их удобно выводить на экран:
cout << a << ", " << b << 'n';
cout << c << ", " << d << 'n';
5. В классе string имеется перегруженная версия оператора +, поэтому можно сложить две строки и получить в качестве результата их конкатенацию. Таким образом, выражение "a" + "b" даст результат "ab". Конкатенация строк a и b с помощью данного способа выполняется довольно легко. При необходимости сложить a и c могут возникнуть некоторые трудности, поскольку c — не строка, а экземпляр класса string_view. Сначала нужно получить строку из c, это делается путем создания новой строки из c и сложения ее с a. Кто-то может задаться вопросом: «Погодите, зачем копировать с в промежуточную строку только для того, чтобы сложить ее с а? Можно ли этого избежать, использовав конструкцию c.data()?» Идея хороша, но имеет недостаток: экземпляры класса string_view не обязаны содержать строки, завершающиеся нулем. Данная проблема может привести к переполнению буфера.
cout << a + b << 'n';
cout << a + string{c} << 'n';
6. Создадим новую строку, содержащую все введенные нами строки и строковые представления. С помощью std::ostringstream можно поместить любую переменную в объект потока, который ведет себя точно так же, как и std::cout, но не выводит данные на консоль. Вместо этого он выводит данные в строковый буфер. После того, как мы поместим все переменные в поток, разделив их пробелами с помощью оператора <<, можем создать и вывести на экран новый объект строки, задействовав конструкцию o.str().
ostringstream o;
o << a << " " << b << " " << c << " " << d;
auto concatenated (o.str());
cout << concatenated << 'n';
7. Мы также можем преобразовать эту новую строку путем, например, перевода всех ее символов в верхний регистр. Библиотечная функция C toupper, которая соотносит символы в нижнем регистре и символы в верхнем, оставляя другие символы неизменными, уже доступна, и ее можно объединить с функцией std::transform, поскольку строка, по сути, представляет собой итерабельный контейнер, содержащий элементы типа char.
transform(begin(concatenated), end(concatenated),
begin(concatenated), ::toupper);
cout << concatenated << 'n';
}
8. Компиляция и запуск программы дадут следующий результат, который полностью оправдывает наши ожидания:
$ ./creating_strings
a, b
c, d
ab
ac
a b c d
A B C D
Как это работает
Очевидно, строки можно складывать с помощью оператора + прямо как числа. Математика здесь не используется, но в итоге мы получаем сконкатенированные строки. Чтобы иметь возможность работать с объектами класса string_view, сначала нужно выполнить их преобразование к типу std::string.
Однако очень важно отметить: при объединении в коде строк и строковых представлений мы никогда не должны предполагать, что хранящаяся в экземпляре класса string_view строка завершается нулевым символом! Именно поэтому мы используем конструкцию "abc"s + string{some_string_view} вместо конструкции "abc"s + some_string_view.data(). Кроме того, класс std::string предоставляет функцию-член append, которая может работать с экземплярами класса string_view, но изменяет строку вместо того, чтобы вернуть новую строку, к которой прикреплено содержимое строкового представления.
Класс std::string_view очень полезен, но будьте осторожны при смешивании его со строками и строковыми функциями. Нельзя рассчитывать на то, что эти строки будут оканчиваться нулями, поэтому весь порядок быстро нарушается в стандартном строковом окружении. К счастью, зачастую предусмотрены подходящие перегруженные версии функций, которые могут обрабатывать подобные ситуации.
Сложную конкатенацию строк с форматированием и т.д. не следует выполнять шаг за шагом для экземпляров строк. Классы std::stringstream, std::ostringstream и std::istringstream подходят для этого гораздо лучше, так как позволяют более качественно управлять памятью при объединении строк и предоставляют все возможности по форматированию, характерные для потоков. Для данного раздела мы выбрали класс std::ostringstream, поскольку собираемся создать строку вместо
Поделиться книгой в соц сетях:
Обратите внимание, что комментарий должен быть не короче 20 символов. Покажите уважение к себе и другим пользователям!