C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц
Книгу C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц читаем онлайн бесплатно полную версию! Чтобы начать читать не надо регистрации. Напомним, что читать онлайн вы можете не только на компьютере, но и на андроид (Android), iPhone и iPad. Приятного чтения!
Шрифт:
Интервал:
Закладка:
Как это делается
В этом примере мы реализуем функцию, которая работает с особенностями класса string_view, а затем увидим, сколько разных типов можем ей передать.
1. Сначала указываем заголовочные файлы и директивы using:
#include <iostream>
#include <string_view>
using namespace std;
2. Реализуем функцию, которая принимает в качестве единственного аргумента объект типа string_view:
void print(string_view v)
{
3. Прежде чем сделать что-то с входной строкой, удалим все пробелы из ее начала и конца. Мы будем изменять не строку, а ее представление, сузив его до значащей части. Функция find_first_not_of найдет первый символ строки, который не является пробелом (' '), символом табуляции ('t') или символом перехода на новую строку ('n'). С помощью функции remove_prefix мы переместим внутренний указатель класса string_view на первый символ, не являющийся пробелом. В том случае, если строка содержит только пробелы, функция find_ first_not_of вернет значение npos, которое равно size_type(-1). Поскольку size_type — беззнаковая переменная, мы получим очень большое число. Поэтому выберем меньшее число из полученных: words_begin или размер строкового представления:
const auto words_begin (v.find_first_not_of(" tn"));
v.remove_prefix(min(words_begin, v.size()));
4. То же самое сделаем с пробелами в конце строки. Функция remove_suffix уменьшает переменную, показывающую размер строкового представления:
const auto words_end (v.find_last_not_of(" tn"));
if (words_end != string_view::npos) {
v.remove_suffix(v.size() - words_end - 1);
}
5. Теперь можно вывести на экран строковое представление и его длину:
cout << "length: " << v.length()
<< " [" << v << "]n";
}
6. В функции main воспользуемся новой функцией print, передав ей разные типы аргументов. Сначала передадим ей во время выполнения строку char* из указателя argv. Во время выполнения программы он будет содержать имя нашего исполняемого файла. Затем передадим ей пустой объект string_view. Далее передадим ей символьную строку, созданную в стиле С, а также строку, образованную с помощью литерала ""sv, который динамически создаст объект типа string_view. И наконец, передадим ей объект класса std::string. Положительный момент заключается в следующем: ни один из данных аргументов не изменяется и не копируется, чтобы вызвать функцию print. Не происходит выделения памяти в куче. Для большого количества строк и/или для длинных строк это очень эффективно.
int main(int argc, char *argv[])
{
print(argv[0]);
print({});
print("a const char * array");
print("an std::string_view literal"sv);
print("an std::string instance"s);
7. Мы не протестировали функцию удаления пробелов. Передадим ей строку, которая содержит множество пробелов в начале и в конце:
print(" tn foobar n t ");
8. Еще одна приятная особенность класса string_view: он позволяет создавать строки, не завершающиеся нулевым символом. Если мы введем строку, например "abc", которая не будет заканчиваться нулем, то функция print сможет безопасно ее обработать, поскольку объект класса string_view также содержит размер строки, на которую указывает:
char cstr[] {'a', 'b', 'c'};
print(string_view(cstr, sizeof(cstr)));
}
9. Компиляция и запуск программы дадут следующий результат. Все строки обработаны корректно. Строка, которую мы заполнили большим количеством пробелов в начале и конце, также была корректно отфильтрована, а строка abc, не имеющая завершающего нулевого символа, корректно выведена на экран, не вызвав переполнения буфера:
$ ./string_view
length: 17 [./string_view]
length: 0 []
length: 20 [a const char * array]
length: 27 [an std::string_view literal]
length: 23 [an std::string instance]
length: 6 [foobar]
length: 3 [abc]
Как это работает
Мы только что увидели следующее: можно вызвать функцию, принимающую аргумент типа string_view, который способен содержать все, что похоже на строку, — а именно символы, сохраненные непрерывным способом. Во время вызовов нашей функции print не было выполнено ни одной операции копирования.
Интересно отметить, что в вызове print(argv[0]) строковое представление автоматически определило длину строки, поскольку данная строка по соглашению завершается нулевым символом. С другой стороны, никто не может предполагать, что можно определить длину поля данных объекта типа string_view путем подсчета символов до тех пор, пока не встретится нулевой символ. Поэтому нужно всегда соблюдать осторожность при работе с указателями на данные строкового представления с помощью string_view::data(). Обычные строковые функции предполагают, что строка будет завершаться нулевым символом, и поэтому использование необработанных указателей способно привести к переполнению буфера. Всегда лучше применять интерфейсы, которые ожидают передачи строкового представления.
За исключением этой особенности, у нас имеется роскошный интерфейс, с которым мы уже знакомы благодаря классу std::string.
Задействуйте класс std::string_view для передачи строк или подстрок, чтобы избежать копирования или выделения памяти кучей, продолжая при этом привычно использовать строковые классы. Но помните: класс std::string_view не предполагает, что строки завершаются нулевым символом.
Считываем значения из пользовательского ввода
Во многих примерах нашей книги значения поступают из входного источника, которым является стандартный поток ввода или файл, а затем с ними выполняются некие действия. В этот раз мы сконцентрируемся лишь на чтении и обработке ошибок, что становится важным, если чтение каких-то данных из потока завершилось неудачей и нужно обработать возникшую ситуацию вместо того, чтобы завершать работу программы.
В следующем примере мы лишь считаем данные от пользователя, но тщательно разобрав этот процесс, вы научитесь читать данные из любого другого потока. Пользовательские данные можно считать с помощью std::cin — по сути, это объект потока ввода, как и экземпляры классов ifstream и istringstream.
Как это делается
В этом примере мы считаем пользовательские данные в разные переменные и увидим, как обрабатывать ошибки, а также научимся выполнять более сложную токенизацию
Прочитали книгу? Предлагаем вам поделится своим отзывом от прочитанного(прослушанного)! Ваш отзыв будет полезен читателям, которые еще только собираются познакомиться с произведением.
Уважаемые читатели, слушатели и просто посетители нашей библиотеки! Просим Вас придерживаться определенных правил при комментировании литературных произведений.
- 1. Просьба отказаться от дискриминационных высказываний. Мы защищаем право наших читателей свободно выражать свою точку зрения. Вместе с тем мы не терпим агрессии. На сайте запрещено оставлять комментарий, который содержит унизительные высказывания или призывы к насилию по отношению к отдельным лицам или группам людей на основании их расы, этнического происхождения, вероисповедания, недееспособности, пола, возраста, статуса ветерана, касты или сексуальной ориентации.
- 2. Просьба отказаться от оскорблений, угроз и запугиваний.
- 3. Просьба отказаться от нецензурной лексики.
- 4. Просьба вести себя максимально корректно как по отношению к авторам, так и по отношению к другим читателям и их комментариям.
Надеемся на Ваше понимание и благоразумие. С уважением, администратор knigkindom.ru.
Оставить комментарий
-
Р.Д.У.22 август 02:17
...мне тоже понравился этот русский вестерн. И озвучено неплохо. Советую....
Силантьев Вадим – Засада
-
Гость Любовь21 август 20:01
Прочитала залпом.... интересный сюжет, история захватывает, плакала вместе с героями. спасибо автору за интересное...
Вернуть жену. Без права на прощение? - Ира Орлова
-
Ма21 август 02:06
Роман хороший, но очень топорный и поэтому скучноватый, все как будто поверхностно, акцент на работе героев - киллер и главбух, а...
Гектор - Ольга Дашкова
