Класс QSharedDataPointer
шаблон <typename T> class QSharedDataPointerКласс QSharedDataPointer представляет указатель на неявно разделяемый объект. Подробнее...
| Заголовок: | #include <QSharedDataPointer> |
| CMake: | find_package(Qt6 COMPONENTS Core REQUIRED) target_link_libraries(mytarget PRIVATE Qt6::Core) |
| qmake: | QT += core |
Примечание: Все функции в этом классе являются реентерабельными.
Открытые типы
| Тип |
Открытые функции
| 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> упрощает написание собственных классов с неявным совместным использованием. QSharedDataPointer реализует безопасную для потоков подсчёт ссылок, гарантируя, что добавление QSharedDataPointers в ваши реентерабельные классы не сделает их нереентерабельными.
Неявное совместное использование используется многими классами 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 имеет конструктор по умолчанию, конструктор копирования и деструктор. Обычно в классе данных для неявно разделяемого класса достаточно тривиальных реализаций этих методов.
Реализация двух конструкторов для класса 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.0/qshareddatapointer.html