C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

C++17 STL Стандартная библиотека шаблонов читать книгу онлайн
С++ — объектно-ориентированный язык программирования, без которого сегодня немыслима промышленная разработка ПО. В этой замечательной книге описана работа с контейнерами, алгоритмами, вспомогательными классами, лямбда-выражениями и другими интересными инструментами, которыми богат современный С++. Освоив материал, вы сможете коренным образом пересмотреть привычный подход к программированию.
Преимущество издания — в подробном описании стандартной библиотеки шаблонов С++, STL. Ее свежая версия была выпущена в 2017 году. В книге вы найдете более 90 максимально реалистичных примеров, которые демонстрируют всю мощь STL. Многие из них станут базовыми кирпичиками для решения более универсальных задач.
Вооружившись этой книгой, вы сможете эффективно использовать С++17 для создания высококачественного и высокопроизводительного ПО, применимого в различных отраслях.
$ ./normalizer src
/Users/tfc/src
6. Когда мы снова запускаем программу в домашнем каталоге, но даем ей запутанное относительное описание пути к файлу, в котором сначала прописывается вход в папку Desktop, потом прописывается выход из нее с помощью косвенного адреса .., затем входим в папку Documents и выходим из нее, чтобы в конечном итоге попасть в каталог src, программа отображает тот же путь файла, что и ранее!
$ ./normalizer Desktop/../Documents/../src
/Users/tfc/src
Как это работает
Этот начальный пример работы с std::filesystem мы сделали относительно коротким и прямолинейным. Мы инициализировали объект класса path на основе строки, которая содержит описание пути к файлу. Класс std::filesystem::path имеет самое первостепенное значение в тех ситуациях, когда мы используем библиотеку, связанную с файловой системой, поскольку с ним связано большинство функций и классов.
Функция filesystem::exists позволяет проверить, существует ли указанный путь файла на самом деле. До сего момента мы не можем быть в этом уверены, поскольку возможно создавать объекты класса path, которые не относятся к реальному объекту файловой системы. Функция exists всего лишь принимает экземпляр класса path и возвращает значение true в том случае, если он действительно существует. Эта функция способна сама определить, какой путь мы ей передали (абсолютный или относительный), что делает ее очень комфортной в применении.
Наконец, мы использовали функцию filesystem::canonical для каталога, чтобы вывести на экран его нормализованную форму:
path canonical(const path& p, const path& base = current_path());
Функция canonical принимает путь к файлу и в качестве необязательного второго аргумента еще один путь к файлу. Второй путь base добавляется к пути файла p в том случае, если p является относительным. После этого функция canonical пытается убрать все косвенные адреса . и .. .
Для вывода результата на экран мы использовали метод .c_str(), которому передали канонический путь к файлу. Мы сделали так потому, что перегруженный оператор << для выходных потоков берет пути к файлам в кавычки, а это не всегда желательно.
Дополнительная информация
Функция canonical генерирует исключение типа fileystem_error, если путь, который мы хотим привести к каноническому виду, не существует. Для предотвращения этого мы проверили наш путь к файлу с помощью функции exists. Но было ли достаточно данной проверки, чтобы необработанные исключения не генерировались? Нет.
Обе функции, как exists, так и canonical, способны генерировать исключения типа bad_alloc. Если бы эти исключения сгенерировались, кто-то мог бы утверждать, что программа все равно обречена. Более важная, а также гораздо более вероятная проблема возникает, когда где-то между проверкой существования файла и процессом приведения его к каноническому виду некто переименовывает или удаляет основной файл! В этом случае функция canonical сгенерирует сообщение об ошибке filesystem_error, хотя мы ранее уже убедились в том, что файл существует.
Большая часть функций файловой системы имеет еще одну перегруженную версию, которая принимает те же аргументы, а также ссылку на std::error_code:
path canonical(const path& p, const path& base = current_path());
path canonical(const path& p, error_code& ec);
path canonical(const std::filesystem::path& p,
const std::filesystem::path& base,
std::error_code& ec);
Таким образом, можно выбрать, окружать ли запросы к функциям файловой системы конструктами try-catch, или же проверять наличие ошибок вручную. Обратите внимание: это изменяет только поведение ошибок, связанных с файловой системой! Если в системе заканчивается память, то возможна генерация более сложных исключений, таких как bad_alloc, которые могут иметь или не иметь параметр ec.
Получаем канонические пути к файлам из относительных путей
В последнем примере мы уже приводили к каноническому виду/нормализовали пути файлов. Конечно же, класс filesystem::path способен не только хранить и проверять пути к файлам. Это помогает легко создавать пути к файлу из строк, а также снова разбивать их на составные части.
На данном этапе класс path позволяет абстрагироваться от деталей работы операционной системы, но в некоторых случаях все же о них следует помнить.
Мы увидим, как обращаться с путями и их композицией/декомпозицией, на примере работы с абсолютными и относительными путями.
Как это делается
В данном примере мы будем работать с абсолютными и относительными путями к файлам, чтобы увидеть сильные стороны класса path и связанных с ним вспомогательных функций.
1. Сначала включаем все необходимые заголовочные файлы и объявляем, что используем пространства имен std и filesystem:
#include <iostream>
#include <filesystem>
using namespace std;
using namespace filesystem;
2. Затем объявляем пример пути к файлу. На данный момент неважно, существует ли текстовый файл, на который он ссылается. Тем не менее есть функции, генерирующие исключения, если требуемого файла нет.
int main()
{
path p {"testdir/foobar.txt"};
3. Сейчас мы познакомимся с четырьмя разными функциями библиотеки для работы с файловой системой. Функция current_path возвращает путь, в котором в данный момент выполняется программа, — так называемый рабочий каталог. Функция absolute принимает относительный путь к файлу наподобие нашего пути p и возвращает абсолютный, однозначный путь во всей файловой системе.
Функция system_complete делает практически то же самое, что и функция absolute в Linux, MacOS или других UNIX-подобных операционных системах. В Windows мы получим абсолютный путь к файлу, только вначале будет добавлено буквенное обозначение тома диска (например, "C:"). Функция canonical опять же делает то же самое, что и функция absolute, но потом дополнительно убирает все косвенные адреса, такие как "." (сокращение для «текущий каталог») или ".." (сокращение для «один каталог вверх»). Мы рассмотрим работу с данными косвенными адресами в следующих шагах.
cout << "current_path : " << current_path()
<< "nabsolute_path : " << absolute(p)
<< "nsystem_complete : " << system_complete(p)
<< "ncanonical(p) : " << canonical(p)
<< 'n';
4. Еще одна приятная особенность класса path заключается в том, что он перегружает оператор /. Таким образом, можно сцеплять имена папок и имена файлов с помощью данного оператора и составлять из них пути файлов. Попробуем это и отобразим составной путь:
cout