Класс QSharedDataPointer
Класс QSharedDataPointer представляет указатель на неявное совместно используемое объект. Подробнее...
| Заголовок: | #include <QSharedDataPointer> |
| qmake: | QT += core |
| С момента: | Qt 4.0 |
Примечание: Все функции в этом классе являются реентерабельными.
Типы публичного доступа
| typedef | Type |
Функции публичного доступа
| QSharedDataPointer() | |
| QSharedDataPointer(T *data) | |
| QSharedDataPointer(const QSharedDataPointer<T> &o) | |
| QSharedDataPointer(QSharedDataPointer<T> &&o) | |
| ~QSharedDataPointer() | |
| const T * | constData() const |
| T * | data() |
| const T * | data() const |
| void | detach() |
| void | swap(QSharedDataPointer<T> &other) |
| T * | operator T *() |
| const T * | operator const T *() const |
| bool | operator!() const |
| bool | operator!=(const QSharedDataPointer<T> &other) const |
| T & | operator*() |
| const T & | operator*() const |
| T * | operator->() |
| const T * | operator->() const |
| QSharedDataPointer<T> & | operator=(const QSharedDataPointer<T> &o) |
| QSharedDataPointer<T> & | operator=(T *o) |
| QSharedDataPointer<T> & | operator=(QSharedDataPointer<T> &&other) |
| bool | operator==(const QSharedDataPointer<T> &other) const |
Защищенные функции
| T * | clone() |
Подробное описание
Класс QSharedDataPointer представляет указатель на неявное совместно используемое объект.
QSharedDataPointer<T> упрощает написание собственных классов с неявным совместным использованием. QSharedDataPointer реализует безопасный для потоков подсчет ссылок, гарантируя, что добавление QSharedDataPointer в ваши реентерабельные классы не сделает их нереентерабельными.
Неявное совместное использование используется многими классами 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.
В нечленной функции класса 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.
В константных членских функциях класса 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, перед изменением имени выполняется копирование при записи. Теперь e1 и e2 указывают на разные EmployeeData объекты. У них разные имена, но оба имеют ID 1001, что, вероятно, не то, что вы хотите. Конечно, можно просто продолжить с e1.setId(1002), если вы действительно хотите создать второго, уникального сотрудника, но если вам нужно только изменить имя сотрудника везде, рассмотрите использование явного совместного использования в классе Employee вместо неявного совместного использования.
Если вы объявите указатель d в классе Employee как QExplicitlySharedDataPointer<EmployeeData>, то используется явное совместное использование, и операции копирование при записи не выполняются автоматически (т.е. detach() не вызывается в неконстантных функциях). В этом случае после e1.setName("Hans Holbein"), имя сотрудника было изменено, но e1 и e2 все равно ссылаются на один и тот же экземпляр EmployeeData, поэтому существует только один сотрудник с ID 1001.
В документации к членам функции указатель d всегда обозначает внутренний указатель на общий объект данных.
Оптимизация производительности для использования в контейнерах Qt
Вы должны рассмотреть возможность маркировки вашего класса с неявным совместным использованием как перемещаемого типа, используя макрос Q_DECLARE_TYPEINFO(), если он похож на класс Employee выше и использует QSharedDataPointer или QExplicitlySharedDataPointer в качестве единственного члена. Это может улучшить производительность и эффективность использования памяти при использовании контейнерных классов Qt.
См. также QSharedData, QExplicitlySharedDataPointer, QScopedPointer и QSharedPointer.
Документация по типам членов
typedef QSharedDataPointer::Type
Это тип общего объекта данных. Указатель d указывает на объект этого типа.
Документация по членам-функциям
QSharedDataPointer::QSharedDataPointer()
Конструирует QSharedDataPointer, инициализированный нулевым указателем d.
QSharedDataPointer::QSharedDataPointer(T *data)
Конструирует QSharedDataPointer с указателем d, установленным на data, и увеличивает счетчик ссылок объекта data.
QSharedDataPointer::QSharedDataPointer(const QSharedDataPointer<T> &o)
Устанавливает указатель d текущего объекта на указатель d в o и увеличивает счетчик ссылок на общий объект данных.
QSharedDataPointer::QSharedDataPointer(QSharedDataPointer<T> &&o)
Перемещающее построение экземпляра QSharedDataPointer, делая его указывающим на тот же объект, на который указывал o.
Эта функция была добавлена в Qt 5.2.
QSharedDataPointer::~QSharedDataPointer()
Уменьшает счетчик ссылок на общий объект данных. Если счетчик ссылок становится равным 0, общий объект данных удаляется. Затем уничтожается текущий объект.
[protected] T *QSharedDataPointer::clone()
Создаёт и возвращает глубокую копию текущих данных. Эта функция вызывается функцией detach() при значении счетчика ссылок больше 1 для создания новой копии. Эта функция использует operator new и вызывает конструктор копирования типа T.
Эта функция предоставляется для поддержки «виртуальных конструкторов копирования» для ваших собственных типов. Для этого следует объявить специализацию шаблона этой функции для вашего собственного типа, как показано в примере ниже:
template<>
EmployeeData *QSharedDataPointer<EmployeeData>::clone()
{
return d->clone();
} В примере выше специализация шаблона для функции clone() вызывает виртуальную функцию EmployeeData::clone(). Класс, производный от EmployeeData, может переопределить эту функцию и вернуть соответствующий полиморфный тип.
Эта функция была добавлена в Qt 4.5.
const T *QSharedDataPointer::constData() const
Возвращает константный указатель на общий объект данных. Эта функция не вызывает detach().
См. также data().
T *QSharedDataPointer::data()
Возвращает указатель на общий объект данных. Эта функция вызывает detach().
См. также constData().
const T *QSharedDataPointer::data() const
Возвращает указатель на общий объект данных. Эта функция не вызывает detach().
void QSharedDataPointer::detach()
Если счетчик ссылок на общий объект данных больше 1, эта функция создает глубокую копию общего объекта данных и устанавливает указатель d текущего объекта на копию.
Эта функция вызывается автоматически неконстантными членами функций QSharedDataPointer, если требуется копирование при записи. Вам не нужно вызывать её самостоятельно.
void QSharedDataPointer::swap(QSharedDataPointer<T> &other)
Меняет местами указатель на общий объект данных текущего объекта и указатель на общий объект данных объекта other.
T *QSharedDataPointer::operator T *()
Возвращает указатель на общий объект данных. Эта функция вызывает detach().
См. также data() и constData().
const T *QSharedDataPointer::operator const T *() const
Возвращает указатель на общий объект данных. Эта функция не вызывает detach().
bool QSharedDataPointer::operator!() const
Возвращает true, если указатель d текущего объекта равен null.
bool QSharedDataPointer::operator!=(const QSharedDataPointer<T> &other) const
Возвращает true, если other и текущий объект не имеют одинаковый указатель d. Эта функция не вызывает detach().
T &QSharedDataPointer::operator*()
Обеспечивает доступ к членам общего объекта данных. Эта функция вызывает detach().
const T &QSharedDataPointer::operator*() const
Обеспечивает константный доступ к членам общего объекта данных. Эта функция не вызывает detach().
T *QSharedDataPointer::operator->()
Обеспечивает доступ к членам общего объекта данных. Эта функция вызывает detach().
const T *QSharedDataPointer::operator->() const
Обеспечивает константный доступ к членам общего объекта данных. Эта функция не вызывает detach().
QSharedDataPointer<T> &QSharedDataPointer::operator=(const QSharedDataPointer<T> &o)
Устанавливает указатель d текущего объекта на указатель d объекта o и увеличивает счетчик ссылок на общий объект данных. Счетчик ссылок на старый общий объект данных текущего объекта уменьшается. Если счетчик ссылок на старый общий объект данных становится равным 0, старый общий объект данных удаляется.
QSharedDataPointer<T> &QSharedDataPointer::operator=(T *o)
Устанавливает указатель d текущего объекта на o и увеличивает счетчик ссылок объекта o. Счетчик ссылок на старый общий объект данных текущего объекта уменьшается. Если счетчик ссылок на старый общий объект данных становится равным 0, старый общий объект данных удаляется.
QSharedDataPointer<T> &QSharedDataPointer::operator=(QSharedDataPointer<T> &&other)
Перемещает other в этот экземпляр QSharedDataPointer.
Эта функция была добавлена в Qt 5.2.
bool QSharedDataPointer::operator==(const QSharedDataPointer<T> &other) const
Возвращает true если other и this имеют тот же указатель d. Эта функция не вызывает detach().
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/archives/qt-5.11/qshareddatapointer.html