Класс QSharedDataPointer
шаблон <typename T> класс QSharedDataPointerКласс QSharedDataPointer представляет указатель на неявное совместно используемое (implicitly shared) объект. Подробнее...
| Заголовок: | #include <QSharedDataPointer> |
| CMake: | find_package(Qt6 COMPONENTS Core REQUIRED) target_link_libraries(mytarget PRIVATE Qt6::Core) |
| qmake: | QT += core |
Примечание: Все функции в этом классе являются реентерабельными.
Публичные типы
| Type |
Публичные функции
| QSharedDataPointer(QSharedDataPointer<T> &&o) | |
| QSharedDataPointer(const QSharedDataPointer<T> &o) | |
| QSharedDataPointer(T *data, QAdoptSharedDataTag) | |
| QSharedDataPointer(T *data) | |
| QSharedDataPointer() | |
| QSharedDataPointer<T> & | operator=(QSharedDataPointer<T> &&other) |
| QSharedDataPointer<T> & | operator=(const QSharedDataPointer<T> &o) |
| ~QSharedDataPointer() | |
| const T * | constData() const |
| T * | data() |
| const T * | data() const |
| void | detach() |
| T * | get() |
| const T * | get() const |
| void | reset(T *ptr = nullptr) |
| void | swap(QSharedDataPointer<T> &other) |
| T * | take() |
| T * | operator T *() |
| const T * | operator const T *() const |
| bool | operator!() const |
| T & | operator*() |
| const T & | operator*() const |
| T * | operator->() |
| const T * | operator->() const |
| QSharedDataPointer<T> & | operator=(T *o) |
Защищенные функции
| T * | clone() |
Связанные нечлены
| bool | operator!=(const QSharedDataPointer<T> &lhs, const QSharedDataPointer<T> &rhs) |
| bool | operator!=(const T *ptr, const QSharedDataPointer<T> &rhs) |
| bool | operator==(const QSharedDataPointer<T> &lhs, const QSharedDataPointer<T> &rhs) |
| bool | operator==(const T *ptr, const QSharedDataPointer<T> &rhs) |
Подробное описание
QSharedDataPointer<T> упрощает написание собственных классов с неявным совместным использованием (implicitly shared). QSharedDataPointer реализует потокобезопасный подсчёт ссылок, гарантируя, что добавление QSharedDataPointers в ваши реентерабельные классы не сделает их нереентерабельными.
Неявное совместное использование (implicit sharing) используется во многих классах Qt для объединения скорости и эффективности памяти указателей с удобством использования классов. См. страницу Общие классы для получения дополнительной информации.
Предположим, вы хотите сделать класс Employee неявно совместно используемым. Процедура такова:
- Определите класс
Employeeс единственным членом данных типаQSharedDataPointer<EmployeeData>. - Определите класс
EmployeeData, унаследованный от QSharedData, для хранения всех членов данных, которые вы обычно помещали в классEmployee.
Чтобы показать это на практике, мы рассмотрим исходный код неявно совместно используемого класса Employee. В файле заголовка мы определяем два класса Employee и EmployeeData.
#include <QSharedData>
#include <QString>
class EmployeeData : public QSharedData
{
public:
EmployeeData() : id(-1) { }
EmployeeData(const EmployeeData &other)
: QSharedData(other), id(other.id), name(other.name) { }
~EmployeeData() { }
int id;
QString name;
};
class Employee
{
public:
Employee() { d = new EmployeeData; }
Employee(int id, const QString &name) {
d = new EmployeeData;
setId(id);
setName(name);
}
Employee(const Employee &other)
: d (other.d)
{
}
void setId(int id) { d->id = id; }
void setName(const QString &name) { d->name = name; }
int id() const { return d->id; }
QString name() const { return d->name; }
private:
QSharedDataPointer<EmployeeData> d;
}; В классе Employee, обратите внимание на единственный член данных — указатель d типа QSharedDataPointer<EmployeeData>. Все обращения к данным сотрудника должны проходить через указатель d с использованием его operator->(). Для записи данных operator->() автоматически вызовет detach(), что создает копию объекта совместно используемых данных, если счётчик ссылок на объект совместно используемых данных больше 1. Это гарантирует, что записи в один объект Employee не повлияют на другие объекты Employee, которые используют тот же объект EmployeeData.
Класс EmployeeData наследует QSharedData, который обеспечивает счётчик ссылок "за кулисами". EmployeeData имеет конструктор по умолчанию, конструктор копирования и деструктор. Обычно тривиальные реализации этих элементов достаточно в классе data для неявно совместно используемого класса.
Реализация двух конструкторов для класса Employee также проста. Оба создают новый экземпляр EmployeeData и присваивают его указателю d.
Employee() { d = new EmployeeData; }
Employee(int id, const QString &name) {
d = new EmployeeData;
setId(id);
setName(name);
} Обратите внимание, что у класса Employee также есть тривиальный конструктор копирования, который в данном случае не является строго обязательным.
Employee(const Employee &other)
: d (other.d)
{
} Конструктор копирования не является строго обязательным здесь, потому что класс EmployeeData включён в тот же файл, что и класс Employee (employee.h). Однако включение частного подкласса QSharedData в тот же файл, что и публичный класс, содержащий QSharedDataPointer, не является типичным. Обычно идея заключается в скрытии частного подкласса QSharedData от пользователя, поместив его в отдельный файл, который не включается в публичный файл. В этом случае мы обычно помещаем класс EmployeeData в отдельный файл, который не включается в employee.h. Вместо этого мы бы просто предварительно объявили частный подкласс EmployeeData в employee.h таким образом:
class EmployeeData;
Если бы мы сделали это здесь, конструктор копирования был бы необходим. Поскольку конструктор копирования тривиален, его можно всегда включать.
За кулисами QSharedDataPointer автоматически увеличивает счётчик ссылок всякий раз, когда объект Employee копируется, присваивается или передаётся в качестве параметра. Он уменьшает счётчик ссылок всякий раз, когда объект Employee удаляется или выходит из области видимости. Объект совместно используемых EmployeeData данных удаляется автоматически, когда счётчик ссылок достигает 0.
В не-const членской функции Employee, всякий раз, когда разыменовывается указатель d, QSharedDataPointer автоматически вызывает detach(), чтобы гарантировать, что функция работает со своей собственной копией данных.
void setId(int id) { d->id = id; }
void setName(const QString &name) { d->name = name; } Обратите внимание, что если detach() вызывается более одного раза в членской функции из-за нескольких разыменовываний указателя d, detach() создаст копию общих данных только в первый раз, если это вообще необходимо, потому что при последующих вызовах detach() счётчик ссылок снова будет равен 1.
Но обратите внимание, что во втором Employee конструкторе, который принимает идентификатор сотрудника и имя, вызываются как setId(), так и setName(), но они не вызывают copy on write, так как счётчик ссылок для только что созданного объекта EmployeeData был установлен в 1.
В const членских функциях Employee разыменование указателя d не вызывает вызов detach().
int id() const { return d->id; }
QString name() const { return d->name; } Обратите внимание, что нет необходимости реализовывать конструктор копирования или оператор присваивания для класса Employee, потому что конструктор копирования и оператор присваивания, предоставляемые компилятором C++, выполнят требуемую поэлементную поверхностную копию. Единственный член, который нужно скопировать, — это указатель d, который является QSharedDataPointer, чья operator=() просто увеличивает счётчик ссылок на общий объект EmployeeData.
Неявное и явное совместное использование
Неявное совместное использование может быть неподходящим для класса Employee. Рассмотрим простой пример, который создаёт два экземпляра класса Employee, использующего неявное совместное использование.
#include "employee.h"
int main()
{
Employee e1(1001, "Albrecht Durer");
Employee e2 = e1;
e1.setName("Hans Holbein");
} После создания второго сотрудника e2 и присваивания e1 ему оба e1 и e2 ссылаются на Альбрехта Дюрера, сотрудника 1001. Оба объекта Employee указывают на тот же экземпляр EmployeeData, который имеет счётчик ссылок 2. Затем вызывается e1.setName("Hans Holbein") для изменения имени сотрудника, но поскольку счётчик ссылок больше 1, copy on write выполняется перед изменением имени. Теперь e1 и e2 указывают на разные объекты EmployeeData. У них разные имена, но оба имеют ID 1001, что, вероятно, не то, что вам нужно. Конечно, вы можете продолжить с e1.setId(1002), если действительно хотите создать второго, уникального сотрудника, но если вы хотите изменить имя сотрудника везде, то рассмотрите использование явного совместного использования в классе Employee вместо неявного совместного использования.
Если вы объявите указатель d в классе Employee как QExplicitlySharedDataPointer<EmployeeData>, то используется явное совместное использование, и операции copy on write не выполняются автоматически (т.е. detach() не вызывается в не-const функциях). В этом случае после e1.setName("Hans Holbein"), имя сотрудника было изменено, но как e1, так и e2 всё ещё ссылаются на тот же экземпляр EmployeeData, поэтому существует только один сотрудник с ID 1001.
В документации к членским функциям указатель d всегда относится к внутреннему указателю на объект общих данных.
Оптимизация производительности для использования в контейнерах Qt
Вы должны рассмотреть возможность маркировки вашего класса с неявным совместным использованием как перемещаемого типа с помощью макроса Q_DECLARE_TYPEINFO(), если он похож на класс Employee выше и использует QSharedDataPointer или QExplicitlySharedDataPointer в качестве единственного члена. Это может повысить производительность и эффективность использования памяти при работе с контейнерными классами Qt.
См. также QSharedData, QExplicitlySharedDataPointer, QScopedPointer и QSharedPointer.
Документация по типу члена
QSharedDataPointer::Type
Это тип объекта общих данных. Указатель d указывает на объект этого типа.
Документация по членским функциям
[since 5.2] QSharedDataPointer::QSharedDataPointer(QSharedDataPointer<T> &&o)
Перемещающее создание экземпляра QSharedDataPointer, делающее его указывающим на тот же объект, на который указывал o.
Эта функция была добавлена в Qt 5.2.
QSharedDataPointer::QSharedDataPointer(const QSharedDataPointer<T> &o)
Устанавливает указатель d данного объекта в указатель d объекта o и увеличивает счётчик ссылок на объект общих данных.
[since 6.0] QSharedDataPointer::QSharedDataPointer(T *data, QAdoptSharedDataTag)
Создаёт QSharedDataPointer с указателем d, установленным на data. Счётчик ссылок data не увеличивается; это можно использовать для принятия указателей, полученных из take().
Эта функция была добавлена в Qt 6.0.
См. также take().
QSharedDataPointer::QSharedDataPointer(T *data)
Создаёт QSharedDataPointer с указателем d, установленным на data, и увеличивает счётчик ссылок data.
QSharedDataPointer::QSharedDataPointer()
Создаёт QSharedDataPointer, инициализированный nullptr как указатель d.
[since 5.2] QSharedDataPointer<T> &QSharedDataPointer::operator=(QSharedDataPointer<T> &&other)
Перемещающее присваивание other данному экземпляру QSharedDataPointer.
Эта функция была добавлена в Qt 5.2.
QSharedDataPointer<T> &QSharedDataPointer::operator=(const QSharedDataPointer<T> &o)
Устанавливает указатель d данного объекта в указатель d объекта o и увеличивает счётчик ссылок на объект общих данных. Счётчик ссылок на старый объект общих данных данного объекта уменьшается. Если счётчик ссылок на старый объект общих данных станет равным 0, старый объект общих данных удаляется.
QSharedDataPointer::~QSharedDataPointer()
Уменьшает счётчик ссылок на объект общих данных. Если счётчик ссылок становится равным 0, объект общих данных удаляется. Данный объект затем уничтожается.
[protected] T *QSharedDataPointer::clone()
Создаёт и возвращает глубокую копию текущих данных. Эта функция вызывается detach() при счётчике ссылок больше 1 для создания новой копии. Эта функция использует operator new и вызывает конструктор копирования типа T.
Эта функция предоставляется для поддержки «виртуальных конструкторов копирования» для ваших собственных типов. Для этого вы должны объявить шаблонную специализацию этой функции для вашего собственного типа, как в примере ниже:
template<>
EmployeeData *QSharedDataPointer<EmployeeData>::clone()
{
return d->clone();
} В примере выше, шаблонная специализация функции clone() вызывает виртуальную функцию EmployeeData::clone(). Класс, производный от EmployeeData, может переопределить эту функцию и вернуть правильный полиморфный тип.
const T *QSharedDataPointer::constData() const
Возвращает указатель типа const на объект общих данных. Эта функция не вызывает detach().
См. также data().
T *QSharedDataPointer::data()
Возвращает указатель на объект общих данных. Эта функция вызывает detach().
См. также constData().
const T *QSharedDataPointer::data() const
Возвращает указатель на объект общих данных. Эта функция не вызывает detach().
void QSharedDataPointer::detach()
Если счётчик ссылок на объект общих данных больше 1, эта функция создаёт глубокую копию объекта общих данных и устанавливает указатель d данного объекта на копию.
Эта функция вызывается автоматически не-const членскими функциями QSharedDataPointer, если требуется copy on write. Вам не нужно вызывать её самостоятельно.
[since 6.0] T *QSharedDataPointer::get()
То же, что и data(). Эта функция предоставляется для совместимости со STL.
Эта функция была добавлена в Qt 6.0.
[since 6.0] const T *QSharedDataPointer::get() const
То же, что и data(). Эта функция предоставляется для совместимости со STL.
Эта функция была добавлена в Qt 6.0.
[since 6.0] void QSharedDataPointer::reset(T *ptr = nullptr)
Устанавливает указатель d данного объекта на ptr и увеличивает счётчик ссылок ptr, если ptr не nullptr. Счётчик ссылок на старый объект общих данных уменьшается, а объект удаляется, если счётчик ссылок достигает 0.
Эта функция была добавлена в Qt 6.0.
void QSharedDataPointer::swap(QSharedDataPointer<T> &other)
Меняет указатель на общие данные этого экземпляра на указатель на общие данные в other.
[since 6.0] T *QSharedDataPointer::take()
Возвращает указатель на общий объект и сбрасывает this в nullptr. (То есть, эта функция устанавливает указатель d объекта this в nullptr.)
Примечание: Счетчик ссылок возвращаемого объекта не будет уменьшен. Эту функцию можно использовать вместе с конструктором, принимающим объект QAdoptSharedDataTag, для передачи объекта общих данных без промежуточных атомарных операций.
Эта функция была добавлена в Qt 6.0.
T *QSharedDataPointer::operator T *()
Возвращает указатель на объект общих данных. Эта функция вызывает detach().
См. также data() и constData().
const T *QSharedDataPointer::operator const T *() const
Возвращает указатель на объект общих данных. Эта функция не вызывает detach().
bool QSharedDataPointer::operator!() const
Возвращает true если указатель d объекта this nullptr.
T &QSharedDataPointer::operator*()
Обеспечивает доступ к членам объекта общих данных. Эта функция вызывает detach().
const T &QSharedDataPointer::operator*() const
Обеспечивает доступ для чтения к членам объекта общих данных. Эта функция не вызывает detach().
T *QSharedDataPointer::operator->()
Обеспечивает доступ к членам объекта общих данных. Эта функция вызывает detach().
const T *QSharedDataPointer::operator->() const
Обеспечивает доступ для чтения к членам объекта общих данных. Эта функция не вызывает detach().
QSharedDataPointer<T> &QSharedDataPointer::operator=(T *o)
Устанавливает указатель d объекта this в o и увеличивает счетчик ссылок o. Счетчик ссылок старого объекта общих данных this уменьшается. Если счетчик ссылок старого объекта общих данных становится 0, старый объект общих данных удаляется.
Связанные нечлены
bool operator!=(const QSharedDataPointer<T> &lhs, const QSharedDataPointer<T> &rhs)
Возвращает true если lhs и rhs не имеют одинаковый указатель d. Эта функция не вызывает detach().
bool operator!=(const T *ptr, const QSharedDataPointer<T> &rhs)
Возвращает true если указатель d объекта rhs не равен ptr. Этот указатель d. Эта функция не вызывает detach().
bool operator==(const QSharedDataPointer<T> &lhs, const QSharedDataPointer<T> &rhs)
Возвращает true если lhs и rhs имеют одинаковый указатель d. Эта функция не вызывает detach().
bool operator==(const T *ptr, const QSharedDataPointer<T> &rhs)
Возвращает true если указатель d объекта rhs равен ptr. Эта функция не вызывает detach().
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.1/qshareddatapointer.html