Неявное совместное использование
Многие классы C++ в Qt используют неявное совместное использование данных, чтобы максимизировать использование ресурсов и свести к минимуму копирование. Неявно разделяемые классы безопасны и эффективны при передаче в качестве аргументов, поскольку передаётся только указатель на данные, а данные копируются только в том случае, если функция записывает в них, т. е. копирование при записи.
Обзор
Разделяемый класс состоит из указателя на общий блок данных, содержащий счётчик ссылок и данные.
При создании разделяемого объекта счётчик ссылок устанавливается в 1. Счётчик ссылок увеличивается всякий раз, когда новый объект ссылается на общие данные, и уменьшается, когда объект перестаёт ссылаться на общие данные. Общие данные удаляются, когда счётчик ссылок становится равным нулю.
При работе с разделяемыми объектами существует два способа копирования объекта. Обычно мы говорим о глубоком и поверхностном копировании. Глубокое копирование подразумевает дублирование объекта. Поверхностное копирование — это ссылка, т. е. просто указатель на общий блок данных. Глубокое копирование может быть дорогостоящим в плане памяти и процессорного времени. Поверхностное копирование очень быстрое, так как оно включает только установку указателя и увеличение счётчика ссылок.
Присваивание объектов (с оператором =()) для неявно разделяемых объектов реализуется с помощью поверхностного копирования.
Преимущество совместного использования заключается в том, что программе не нужно излишне дублировать данные, что приводит к меньшему использованию памяти и меньшему копированию данных. Объекты можно легко присваивать, отправлять в качестве аргументов функций и возвращать из функций.
Неявное совместное использование в основном происходит за кулисами; программисту редко нужно о нём беспокоиться. Однако итераторы контейнеров Qt ведут себя иначе, чем итераторы STL. Читайте проблему с итераторами при неявном совместном использовании.
В многопоточных приложениях неявное совместное использование происходит, как описано в разделе о потоках и неявно разделяемых классах.
При реализации собственных неявно разделяемых классов используйте классы QSharedData и QSharedDataPointer.
Подробное описание неявного совместного использования
Неявное совместное использование автоматически отсоединяет объект от общего блока, если объект собирается изменить, а счётчик ссылок больше единицы. (Это часто называется копированием при записи или семантикой значения.)
Неявно разделяемый класс управляет своими внутренними данными. В любых методах-членах, изменяющих его данные, он автоматически отсоединяется перед изменением данных. Однако обратите внимание на особый случай с итераторами контейнеров; см. проблему с итераторами при неявном совместном использовании.
Класс QPen, который использует неявное совместное использование, отсоединяется от общих данных во всех методах-членах, изменяющих внутренние данные.
Фрагмент кода:
void QPen::setStyle(Qt::PenStyle style)
{
detach(); // detach from common data
d->style = style; // set the style member
}
void QPen::detach()
{
if (d->ref != 1) {
... // perform a deep copy
}
} Список классов
Нижеперечисленные классы автоматически отсоединяются от общих данных, если объект собирается изменить. Программист даже не заметит, что объекты разделяют данные. Поэтому следует рассматривать отдельные экземпляры этих классов как отдельные объекты. Они всегда будут вести себя как отдельные объекты, но с дополнительной возможностью совместного использования данных, когда это возможно. По этой причине вы можете передавать экземпляры этих классов в функции по значению без опасений относительно накладных расходов на копирование.
Пример:
QPixmap p1, p2;
p1.load("image.bmp");
p2 = p1; // p1 and p2 share data
QPainter paint;
paint.begin(&p2); // cuts p2 loose from p1
paint.drawText(0,50, "Hi");
paint.end(); В этом примере p1 и p2 делят данные до вызова QPainter::begin() для p2, поскольку рисование пиксельной карты приведет к её изменению.
Предупреждение: Будьте осторожны при копировании неявно разделяемого контейнера (QMap, QVector и т. д.) при использовании итераторов в стиле STL. См. проблему с итераторами при неявном совместном использовании.
Массив битов |
|
Монохромные (глубина 1 бит) пикчеры |
|
Определяет образец заливки фигур, нарисованных QPainter |
|
Массив байтов |
|
Список массивов байтов |
|
Шаблонный класс, предоставляющий кэш |
|
Сравнивает строки в соответствии с локальным алгоритмом сортировки |
|
Может быть использован для ускорения сортировки строк |
|
Определяет возможный параметр командной строки |
|
Шаблонный класс, предоставляющий непрерывный кэш |
|
Курсор мыши с произвольной формой |
|
Относится к одному ожидающему асинхронному вызову |
|
Содержит один дескриптор Unix-файла |
|
Функции даты и времени |
|
Поток вывода для отладочной информации |
|
Доступ к структурам каталогов и их содержимому |
|
Хранит информацию о записи доменного имени |
|
Хранит информацию о записи адреса хоста |
|
Хранит информацию о записи MX DNS |
|
Хранит информацию о записи SRV DNS |
|
Хранит информацию о записи TXT DNS |
|
Независимая от платформы информация о файле |
|
Указывает запрос для шрифта, используемого для отображения текста |
|
Общая информация о шрифтах |
|
Информация о метриках шрифта |
|
Информация о метриках шрифта |
|
Прямой доступ к внутренним глифам в шрифте |
|
Используется совместно с QBrush для указания градиентных заливок |
|
Шаблонный класс, предоставляющий словарь на основе хеш-таблицы |
|
IP-адрес |
|
Управляет параметрами и настройками HTTP/2 |
|
Хранит часть тела для использования внутри сообщения HTTP multipart MIME |
|
Масштабируемые значки в различных режимах и состояниях |
|
Независимая от аппаратной части представление изображения, позволяющее напрямую получить доступ к пиксельным данным и может быть использовано в качестве устройства рисования |
|
Инкапсулирует массив JSON |
|
Способ чтения и записи документов JSON |
|
Инкапсулирует объект JSON |
|
Используется для отчета об ошибках во время разбора JSON |
|
Инкапсулирует значение в JSON |
|
Инкапсулирует последовательность нажатий клавиш, как в сочетаниях клавиш |
|
Шаблонный класс, предоставляющий списки |
|
Преобразует числа в их строковые представления на различных языках |
|
Шаблонный класс, предоставляющий словарь на основе красных-черных деревьев |
|
Описывает типы файлов или данных, представленные строкой MIME-типа |
|
Удобный подкласс QHash, который предоставляет хеши с несколькими значениями |
|
Удобный подкласс QMap, который предоставляет карты с несколькими значениями |
|
Хранит один IP-адрес, поддерживаемый сетевым интерфейсом, вместе с его ассоциированной маской сети и адресом широковещания |
|
Информация о кэше |
|
Хранит один сетевой cookie |
|
Список IP-адресов и сетевых интерфейсов хоста |
|
Прокси-сервер сетевого уровня |
|
Используется для запроса параметров прокси для сокета |
|
Хранит запрос, который необходимо отправить с помощью QNetworkAccessManager |
|
Оборачивает сообщение об отладке OpenGL |
|
Контейнер для операций рисования, позволяющий строить и повторно использовать графические фигуры |
|
Содержит группы цветов для каждого состояния виджета |
|
Определяет, как QPainter должен рисовать линии и контуры фигур |
|
Используется для поиска данных в модели данных |
|
Устройство рисования, которое записывает и воспроизводит команды QPainter |
|
Представление изображения вне экрана, которое может использоваться в качестве устройства рисования |
|
Вектор точек с целочисленной точностью |
|
Вектор точек с плавающей точкой |
|
Содержит переменные среды, которые могут быть переданы программе |
|
Обобщенный контейнер, предоставляющий очередь |
|
Доступ к одному физическому экземпляру шрифта |
Сопоставление с образцом с помощью регулярных выражений |
|
Определяет область обрезки для художника |
|
Сопоставление с образцом с помощью регулярных выражений |
|
Результаты сопоставления QRegularExpression со строкой |
|
Итератор по результатам глобального сопоставления объекта QRegularExpression со строкой |
|
Шаблонный класс, который предоставляет множество на основе хеш-таблицы |
|
Удобный API для сертификата X509 |
|
API для доступа к расширениям сертификата X509 |
|
Представляет криптографический шифр SSL |
|
Содержит конфигурацию и состояние соединения SSL |
|
Интерфейс для параметров Diffie-Hellman для серверов |
|
Ошибка SSL |
|
Интерфейс для закрытых и открытых ключей |
|
Данные аутентификации для шифров с предварительно общими ключами (PSK) |
|
Шаблонный класс, который предоставляет стек |
|
Обеспечивает оптимизированный вывод текста, когда текст и его расположение обновляются редко |
|
Предоставляет информацию о подключённых хранилищах и накопителях |
|
Строка Unicode |
|
Список строк |
|
Информация о форматировании блоков текста в QTextDocument |
|
Способ нахождения границ текста Unicode в строке |
|
Информация о форматировании символов в QTextDocument |
|
Предлагает API для доступа к QTextDocument и изменения его |
|
Представляет фрагмент форматированного текста из QTextDocument |
|
Информация о форматировании QTextDocument |
|
Информация о форматировании фреймов в QTextDocument |
|
Информация о форматировании изображений в QTextDocument |
|
Информация о форматировании списков в QTextDocument |
|
Информация о форматировании ячеек таблицы в QTextDocument |
|
Информация о форматировании таблиц в QTextDocument |
|
Удобный интерфейс для работы с URL-адресами |
|
Способ манипулирования парами ключ-значение в запросе URL |
|
Выступает как объединение для наиболее распространённых типов данных Qt |
|
Шаблонный класс, который предоставляет динамический массив |
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.15/implicit-sharing.html