Д. Стефенс - C++. Сборник рецептов
- Название:C++. Сборник рецептов
- Автор:
- Жанр:
- Издательство:КУДИЦ-ПРЕСС
- Год:2007
- Город:Москва
- ISBN:5-91136-030-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Д. Стефенс - C++. Сборник рецептов краткое содержание
Данная книга написана экспертами по C++ и содержит готовые рецепты решения каждодневных задач для программистов на С++. Один из авторов является создателем библиотеки Boost Iostreams и нескольких других библиотек C++ с открытым исходным кодом. В книге затрагивается множество тем, вот лишь некоторые из них: работа с датой и временем; потоковый ввод/вывод; обработка исключений; работа с классами и объектами; сборка приложений; синтаксический анализ XML-документов; программирование математических задач. Читатель сможет использовать готовые решения, а сэкономленное время и усилия направить на решение конкретных задач.
C++. Сборник рецептов - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Пример 4.5. Использование функций обрезки строк Boost
#include
#include
#include
using namespace std;
using namespace boost;
int main() {
string s1 = " ведущие пробелы?";
trim_left(s1); // Обрезка оригинальной строки
string s2 = trim_left_copy(s1); // Обрезка, но оригинал остается без изменений
cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2 << endl;
s1 = "YYYYboostXXX";
s2 = trim_copy_if(s1, is_any_of("XY")); // Используется предикат
trim_if(s1, is_any_of("XY"));
cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2 << endl;
s1 = "1234 числа 9876";
s2 = trim_copy_if(s1, is_digit());
cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2 << endl;
// Вложенные вызовы функций обрезки
s1 = " ****Обрезка!*** ";
s2 = trim_copy_if(trim_copy(s1), is_any_of("*"));
cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2 << endl;
}
Пример 4.5 демонстрирует, как использовать функции обрезки строк Boost. Обычно способ их использования понятен из их названия, так что я не буду вдаваться в описания более подробные, чем даны в табл. 4.1. Единственная функция, имеющаяся в этом примере и отсутствующая в таблице, — это is_any_of
. Это шаблон функции, который возвращает объект функции-предиката, используемый функциями серии trim_if
. Она используется, когда требуется обрезать набор символов. Также есть аналогичная функция классификации, которая называется is_from_range
и принимает два аргумента и возвращает унарный предикат, который возвращает истину, когда символ находится в заданном диапазоне. Например, чтобы обрезать в строке символы с а
до d
, требуется сделать что-то, похожее на следующее.
s1 = "abcdXXXabcd";
trim_if(s1, is_from_range('a', 'd'));
cout << "s1 = " << s1 << endl; // Теперь s1 = XXX
Заметьте, что эта конструкция чувствительна к регистру, так как диапазон от а
до d
не включает заглавных версий этих букв.
4.3. Хранение строк в последовательности
Требуется сохранить набор строк в виде последовательности, которая ведет себя как массив.
Для хранения строк в виде массива используйте vector
. Пример 4.6 показывает простой образец.
Пример 4 6. Хранение строк в векторе
#include
#include
#include
using namespace std;
int main() {
vector v;
string s = "one";
v.push_back(s);
s = "two";
v.push_back(s);
s = "three";
v.push_back(s);
for (int i = 0; i < v.size(); ++i) {
cout << v[i] << "\n";
}
}
vector
использует для произвольного доступа семантику массива (а также делает много другого), так что он прост и понятен в использовании. Однако vector
— это только одна из многих последовательностей стандартной библиотеки. Чтобы узнать об этом побольше, читайте дальше.
vector
— это динамическая последовательность объектов, которая предоставляет произвольный доступ с помощью оператора в стиле массивов operator[]
. Метод push_back
при помощи копирующего конструктора копирует свой аргумент, добавляет копию в последний элемент вектора и увеличивает его размер на единицу. pop_back
выполняет обратную операцию, удаляя последний элемент. Вставка и удаление элементов в конце вектора занимает постоянное время, а время вставки и удаления элементов в середине вектора линейно зависит от его размера. Это основы векторов. Кроме этого, они умеют еще много чего.
В большинстве случаев vector
должен быть первым выбором вместо массива в стиле С. Во-первых, их размеры изменяются динамически, что означает, что эти размеры увеличиваются по мере необходимости. Не требуется проводить каких-либо исследований для выбора оптимального размера статического массива, как в случае с массивами С, — vector растет по мере надобности, а при необходимости может быть увеличен или уменьшен вручную. Во-вторых, vector
при использовании метода at
(но не при использовании operator[]
) предлагает проверку границ, так что при ссылке на несуществующий индекс программа не обрушится и не продолжит выполнение с неверными данными. Посмотрите на пример 4.7, Он показывает, как работать с индексами, выходящими за границы массива.
Пример 4.7. Проверка границ для векторов
#include
#include
#include
using namespace std;
int main() {
char carr[] = {'a', 'b', 'c', 'd', 'e'};
cout << carr[100000] << '\n'; // Оп, кто знает, что дальше
// произойдет
vector v;
v.push_back('a');
v.push_back('b');
v.push_back('c');
v.push_back('d');
v push_back('e');
try {
cout << v.at(10000) << "\n"; // at проверяет границы и выбрасывает
} catch(out_of_range& е) { // out_of_range, если произошел выход за них
cerr << e.what() << '\n';
}
}
Перехват out_of_range
, определенного в , позволяет грамотно справиться с неправильными индексами. А также можно вызвать метод what
, позволяющий в зависимости от используемой реализации получить осмысленное сообщение об ошибке, как возвращаемая в коде примера 4.7:
invalid vector subscript
Однако vector
не является единственной возможностью. В C++ имеется большое количество способов хранить последовательности. Кроме vector
имеются list
, set
и двунаправленные очереди ( deque
— double-ended queue). Все они поддерживают множество одинаковых операций, и каждый поддерживает свои собственные. Кроме того, каждый имеет различную алгоритмическую сложность, требования по хранению и семантику. Так что имеется богатый выбор.
Посмотрите внимательно на пример 4.6. Вы, вероятно, обратите внимание, что я изменяю значение строки s
до того, как добавляю ее в конец контейнера с помощью push_back
. Логично ожидать такого вывода этого примера
three
three
three
Я поместил в вектор одну и ту же строку три раза, так что каждый раз, когда я переприсваиваю строку, разве не должны все элементы вектора указывать на одну и ту же строку? Нет. Это важный момент, касающийся контейнеров STL.
Контейнеры STL сохраняют копии объектов, помещаемых в них, а не сами объекты. Так что после помещения в контейнер всех трех строк в памяти остается четыре строки: три копии, созданные и хранящиеся в контейнере, и одна копия, которой присваиваются значения.
Ну и что? Было создано несколько новых копий: большое дело. Но это действительно большое дело, так как если используется большое количество строк, за каждую копию приходится платить процессорным временем, памятью или и тем и другим. Копирование элементов в контейнерах — это намеренное поведение STL, и все контейнеры организованы именно так.
Читать дальшеИнтервал:
Закладка: