C++. Сборник рецептов - [95]
6.9. Хранение контейнеров в контейнерах
Имеется несколько экземпляров стандартного контейнера (>list
, >set
и т.п.) и требуется сохранить их в еще одном контейнере.
Сохраните в главном контейнере указатели на остальные контейнеры. Например, можно использовать >map
для хранения ключа типа >string
и указателя на >set
как значения. Пример 6.12 показывает простой класс журналирования транзакций, который хранит данные как map из пар, состоящих из >string
и указателей на >set
.
Пример 6.12. Хранение набора указателей в отображении
>#include
>#include
>#include
>#include
>using namespace std;
>typedef set
>typedef map
>// Фиктивный класс базы данных
>class DBConn {
>public:
> void beginTxn() {}
> void endTxn() {}
> void execSql(string& sql) {}
>};
>class SimpleTxnLog {
>public:
> SimpleTxrLog() {}
> ~SimpleTxrLog() {purge();}
> // Добавляем в список выражение SQL
> void addTxn(const string& id
> const string& sql) {
> SetStr* pSet = log_[id]; // Здесь создается запись для
> if (pSet == NULL) { // данного id, если ее еще нет
> pSet = new SetStr();
> log_[id] = pSet;
> }
> pSet->insert(sol);
> }
> // Применение выражений SQL к базе данных, по одной транзакции
> // за один раз
> void apply() {
> for (MapStrSetStr::iterator p = log_.begin();
> p != log_.end(); ++p) {
> conn_->beginTxn();
> // Помните, что итератор отображения ссылается на объект
> // типа pair
> for (SetStr::iterator pSql = p->second->begin();
> pSql != p->second->end(); ++pSql) {
> string s = *pSql;
> conn_->execSql(s);
> cout << "Executing SQL: " << s << endl;
> }
> conn_->endTxn();
> delete p->second;
> }
> log_.clear();
> }
> void purge() {
> for (MapStrSetStr::iterator p = log_.begin();
> p != log_.end(); ++p)
> delete p->second;
> log_.clear();
> }
> //...
>private:
> MapStrSetStr log_;
> DBConn* conn_;
>}
;
Пример 6.12 предлагает ситуацию, где может потребоваться хранение одного контейнера в другом. Представьте, что требуется сохранить набор выражений SQL в виде пакета, выполнить их в будущем все сразу для реляционной базы данных. Именно это делает >SimpleTxnLog
. Чтобы сделать его еще полезнее, можно добавить в него другие методы, а для обеспечения безопасности — добавить обработку исключений, но целью этого примера является показать, как хранить один тип контейнеров в другом.
Для начала я создаю несколько >typedef
, облегчающих чтение кода.
>typedef std::set
>typedef std::map
При использовании шаблонов шаблонов (шаблонов… и т.д.) объявления становятся очень длинными, что затрудняет их чтение, так что облегчите себе жизнь, использовав >typedef
. Более того, использование >typedef
облегчает внесение изменений в объявление шаблонов, избавляя от необходимости выполнять поиск и замену во многих местах большого количества исходных файлов.
Класс >DBConn
— это фиктивный класс, который представляет подключение к реляционной базе данных. Интересно здесь то, как в >SimpleTxnLog
определяется метод >addTxn
. В начале этой функции я смотрю, существует ли уже объект набора для переданного >id
.
>SetStr* pSet = log_[id];
>log_
— это >map
(см. рецепт 6.6), так что >operator[]
выполняет поиск >id
и смотрит, связаны ли с ним какие-либо данные. Если да, то возвращается объект данных, и >pSet
не равен >NULL
. Если нет, он создается, и возвращается указатель, который будет равен >NULL
. Затем я проверяю, указывает ли на что-то >pSet
, и определяю, требуется ли создать еще один набор.
>if (pSet == NULL) {
> pSet = new SetStr(); // SetStr = std::set
> log_[id] = pSet;
>}
Так как >pSet
— это копия объекта данных, хранящихся в map (указатель на набор), а не само значение, то после создания >set
я должен поместить его обратно в связанный с ним ключ в >map
. После этого все, что остается сделать, — это добавить элемент в набор и выйти.
>pSet->insert(sql);
Выполнив указанные шаги, я в один контейнер (>map
) добавил указатель на адрес другого контейнера (>set
). Что я не делал — это добавление объекта>set
в >map
. Разница очень существенна. Так как контейнеры обладают семантикой копирования, следующий код приведет к копированию всего набора >s
в >map
.
>set
>// Заполнить s данными...
>log_[id] = s; // Скопировать s и добавить его копию в log_
Это приведет к огромному числу дополнительных нежелательных копирований. Следовательно, общее правило при использовании контейнеров из контейнеров — это использовать указатели на контейнеры.
Глава 7
Алгоритмы
7.0. Введение
Эта глава рассказывает, как работать со стандартными алгоритмами и как использовать их для стандартных контейнеров. Эти алгоритмы первоначально являлись частью того, что часто называется Standard Template Library (STL — стандартная библиотека шаблонов) и представляет собой набор алгоритмов, итераторов и контейнеров, которые теперь вошли в стандартную библиотеку (глава 6 содержит рецепты по работе со стандартными контейнерами). Я их буду называть просто стандартными алгоритмами, итераторами и контейнерами, но не забывайте, что это то же самое, что другие авторы называют частью STL. Одним из базовых элементов стандартной библиотеки являются итераторы, так что первый рецепт описывает, что они собой представляют и как их использовать. После этого идет несколько рецептов, которые объясняют, как использовать и расширять стандартные алгоритмы. Наконец, если вы не нашли ничего подходящего в стандартной библиотеке, то рецепт 7.10 расскажет, как написать собственный алгоритм.
Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)
Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.
Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.
Система сборки программ, используемая во FreeBSD, имеет значительно большие возможности, чем те, которые мы задействовали. Какие это возможности и как их использовать в своих портах?
Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.
«Как пасти котов» – это книга о лидерстве и руководстве, о том, как первое совмещать со вторым. Это, если хотите, словарь трудных случаев управления IT-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.