- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
QT 4: программирование GUI на С++ - Жасмин Бланшет
Шрифт:
Интервал:
Закладка:
В отличие от этого подхода, STL склоняет нас к передаче вектора в виде неконстантной ссылки, чтобы избежать копирования, происходящего из-за возвращения функцией значения, хранимого в переменной:
01 using namespace std;
02 void sineTable(vector<double> &vect)
03 {
04 vect.resize(360);
05 for (int i = 0; i < 360; ++i)
06 vect[i] = sin(i / (2 * M_PI));
07 }
В результате вызов будет не столь простым и менее понятным:
vector<double> table;
sineTable(table);
В Qt применяется неявное совместное использование данных во всех ее контейнерах и во многих других классах, включая QByteArray, QBrush, QFont, QImage, QPixmap и QString. Это делает применение этих классов очень эффективным при передаче по значению, как аргументов функции, так и возвращаемых функциями значений.
Неявное совместное использование данных в Qt гарантирует, что данные не будут копироваться, если мы их не модифицируем. Чтобы получить максимальные выгоды от применения этой технологии, необходимо выработать в себе две новые привычки при программировании. Одна связана с использованием функции at() вместо оператора [ ] при доступе только для чтения к (неконстантному) вектору или списку. Поскольку при применении Qt—контейнеров нельзя сказать, оказывается ли [ ] с левой стороны оператора присваивания или нет, предполагается самое худшее и принудительно выполняется действительное копирование (deep сору), в то время как at() не допускается в левой части оператора присваивания.
Подобная проблема возникает при прохождении контейнера с помощью итераторов в стиле STL. Когда вызываются функции begin() или end() для неконстантного контейнера, Qt всегда принудительно выполняет действительное копирование при совместном использовании данных. Решение, позволяющее избавиться от этой неэффективности, состоит в применении по мере возможности const_iterator, constBegin() и constEnd().
В Qt предусмотрен еще один, последний метод прохода по элементам последовательного контейнера — оператор цикла foreach. Он выглядит следующим образом:
QLinkedList<Movie> list;
…
foreach (Movie movie, list) {
if (movie.title() == "Citizen Kane") {
cout << "Found Citizen Kane" << endl;
break;
}
}
Псевдоключевое слово foreach реализуется с помощью стандартного цикла for. На каждом шаге цикла переменная цикла (movie) устанавливается на новый элемент, начиная с первого элемента контейнера и затем двигаясь вперед. Цикл foreach автоматически использует копию контейнера при входе в цикл, и по этой причине модификации контейнера в ходе цикла не влияют на сам цикл.
Поддерживаются операторы цикла break и continue. Если тело цикла состоит из одного оператора, необязательно указывать скобки. Как и для оператора for, переменная цикла может определяться вне цикла, например:
QLinkedList<Movie> list;
Movie movie;
…
foreach (movie, list) {
if (movie.title() == "Citizen Kane") {
cout << "Found Citizen Kane" << endl;
break;
}
}
Определение переменной цикла вне цикла — единственная возможность для контейнеров, содержащих типы данных с запятой (например, QPair<QString, int>).
Как работает неявное совместное использование данных
Неявное совместное использование данных работает автоматически и незаметно для пользователя, поэтому нам не надо в программном коде предусматривать специальные операторы для обеспечения этой оптимизации. Но поскольку хочется знать, как это работает, мы рассмотрим пример и увидим, что скрывается от нашего внимания. В этом примере используются строки типа QString — одного из многих неявно совместно используемых Qt—классов:
QString str1 = "Humpty";
QString str2 = str1;
Мы присваиваем переменной str1 значение «Humpty» (Humpty-Dumpty — Шалтай—Болтай) и переменную str2 приравниваем к переменной str1. К этому моменту оба объекта QString ссылаются на одну и ту же внутреннюю структуру данных в памяти. Кроме символьных данных эта структура данных имеет счетчик ссылок, показывающий, сколько строк QString ссылается на одну структуру данных. Поскольку обе переменные ссылаются на одни данные, счетчик ссылок будет иметь значение 2.
str2[0] = 'D';
Когда мы модифицируем переменную str2, выполняется действительное копирование данных, чтобы переменные str1 и str2 ссылались на разные структуры данных и их изменение приводило к изменению их собственных копий данных. Счетчик ссылок данных переменной str1 («Humpty») принимает значение 1, и счетчик ссылок данных переменной str2 («Dumpty») тоже принимает значение 1. Значение 1 счетчика ссылок означает, что данные не используются совместно.
str2.truncate(4);
Если мы снова модифицируем переменную str2, никакого копирования не будет происходить, поскольку счетчик ссылок данных переменной str2 имеет значение 1. Функция truncate() непосредственно обрабатывает значение переменной str2, возвращая в результате строку «Dump». Счетчик ссылок по-прежнему имеет значение 1.
str1 = str2;
Когда мы присваиваем строку str2 строке str1, счетчик ссылок для данных str1 снижается до 0 и приводит к тому, что теперь никакая строка типа QString не содержит значения «Humpty». Память освобождается. Обе строки QStrings теперь ссылаются на значение «Dump», счетчик ссылок которого теперь имеет значение 2.
Часто не пользуются возможностью совместного использования данных в многопоточных программах из-за условий гонок при доступе к счетчикам ссылок. В Qt этой проблемы не возникает. Классы—контейнеры используют инструкции ассемблера при реализации атомарных операций со счетчиками. Эта технология доступна пользователям Qt через применение классов QSharedData и QSharedDataPointer.
Ассоциативные контейнеры
Ассоциативный контейнер содержит произвольное количество элементов одинакового типа, индексируемых некоторым ключом. Qt содержит два основных класса ассоциативных контейнеров: QМар<К, T> и QHash<K, T>.
QMap<K, T> — это структура данных, которая содержит пары ключ—значение, упорядоченные по возрастанию ключей. Такая организация данных обеспечивает хорошую производительность операций поиска и вставки, а также при проходе данных в порядке их сортировки. Внутренне QMap<K, T> реализуется как слоеный список (skip—list).
Рис. 11.6. Ассоциативный массив, связывающий QString с int.
Простой способ вставки элементов в ассоциативный массив состоит в использовании функции insert():
QMap<QString, int> map;
map.insert("eins", 1);
map.insert("sieben", 7);
map.insert("dreiundzwanzig", 23);
Можно поступить по-другому — просто присвоить значение заданному ключу:
map["eins"] = 1;
map["sieben"] = 7;
map["dreiundzwanzig"] = 23;
Оператор [ ] может использоваться как для вставки, так и для поиска. Но если этот оператор используется для поиска значения, для которого не существует ключа, будет создан новый элемент с данным ключом и пустым значением. Чтобы не создавать случайно пустые элементы, вместо оператора [ ] можно использовать функцию value():
int val = map.value("dreiundzwanzig");
Если ключ отсутствует в ассоциативном массиве, возвращается значение по умолчанию, создаваемое стандартным конструктором данного типа значений. Для базовых типов и указателей возвращается нуль. Мы можем определить другое значение, используемое по умолчанию, с помощью второго аргумента функции value(), например:
int seconds = map.value("delay", 30);
Это эквивалентно следующим операторам:
int seconds = 30;
if (map.contains("delay"))
seconds = map.value("delay");
Типы данных К и T в ассоциативном массиве QMap<K, T> могут быть базовыми типами (например, int и double), указатели и классы, которые имеют стандартный конструктор, конструктор копирования и оператор присваивания. Кроме того, тип К должен обеспечивать оператор operator < (), поскольку QMap<K, T> применяет его для хранения элементов в порядке возрастания значений ключей.
Класс QMap<K, T> имеет две удобные функции, keys() и values(), которые особенно полезны при работе с небольшими наборами данных. Они возвращают списки типа QList ключей и значений ассоциативного массива.

