Spec-Zone.ru › Qt 5.14

Класс QSharedDataPointer

Класс QSharedDataPointer представляет указатель на неявное совместно используемое объект. Подробнее...

Заголовок: #include <QSharedDataPointer>
qmake: QT += core
С тех пор: Qt 4.0

Этот класс был представлен в Qt 4.0.

  • Список всех членов, включая унаследованные

Примечание: Все функции в этом классе являются перевходоустойчивыми.

Открытые типы

typedef Type

Открытые функции

QSharedDataPointer(QSharedDataPointer<T> &&o)
QSharedDataPointer(const QSharedDataPointer<T> &o)
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()
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=(T *o)
bool operator==(const QSharedDataPointer<T> &other) const

Защищённые функции

T * clone()

Подробное описание

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 имеет конструктор по умолчанию, конструктор копирования и деструктор. Обычно для неявного совместно используемого класса в классе 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.

В неконстантном методе 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, чья операция копирования просто увеличивает счётчик ссылок общих данных 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. У них разные имена, но оба имеют идентификатор 1001, что, вероятно, не то, что вам нужно. Конечно, вы можете просто продолжить с e1.setId(1002), если действительно хотите создать второго, уникального сотрудника, но если вы хотите только изменить имя сотрудника повсюду, рассмотрите использование явного совместного использования в классе Employee вместо неявного совместного использования.

Если вы объявите указатель d в классе Employee как QExplicitlySharedDataPointer<EmployeeData>, то будет использоваться явное совместное использование, и операции copy on write не будут выполняться автоматически (т.е. detach() не вызывается в неконстантных функциях). В этом случае после e1.setName("Hans Holbein"), имя сотрудника было изменено, но e1 и e2 по-прежнему ссылаются на один и тот же экземпляр EmployeeData, поэтому существует только один сотрудник с идентификатором 1001.

В документации к членам функции d указатель всегда ссылается на внутренний указатель на объект совместно используемых данных.

Оптимизация производительности для использования в контейнерах Qt

Если ваш неявно совместно используемый класс похож на класс Employee выше и использует QSharedDataPointer или QExplicitlySharedDataPointer в качестве единственного члена, следует пометить его как перемещаемый тип, используя макрос Q_DECLARE_TYPEINFO(). Это может улучшить производительность и эффективность использования памяти при работе с контейнерными классами Qt.

См. также QSharedData, QExplicitlySharedDataPointer, QScopedPointer и QSharedPointer.

Документация по типу члена

typedef QSharedDataPointer::Type

Это тип объекта совместно используемых данных. Указатель d указывает на объект этого типа.

Документация по членам функции

QSharedDataPointer::QSharedDataPointer(QSharedDataPointer<T> &&o)

Создает экземпляр QSharedDataPointer путем перемещения, делая его указывающим на тот же объект, на который указывал o.

Эта функция была добавлена в Qt 5.2.

QSharedDataPointer::QSharedDataPointer(const QSharedDataPointer<T> &o)

Устанавливает указатель d для этого на указатель d в o и увеличивает счетчик ссылок на объект совместно используемых данных.

QSharedDataPointer::QSharedDataPointer(T *data)

Создает QSharedDataPointer с указателем d, установленным на data, и увеличивает счетчик ссылок для data.

QSharedDataPointer::QSharedDataPointer()

Создает QSharedDataPointer, инициализированный значением nullptr в качестве указателя d.

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, может переопределить эту функцию и вернуть соответствующий полиморфный тип.

Эта функция была добавлена в 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, если требуется copy on write. Вам не нужно вызывать её самостоятельно.

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 для этого равен nullptr.

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=(T *o)

Устанавливает указатель d для этого на o и увеличивает счетчик ссылок для o. Счетчик ссылок на старый объект совместно используемых данных этого уменьшается. Если счетчик ссылок на старый объект совместно используемых данных становится равным 0, старый объект совместно используемых данных удаляется.

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/qt-5.14/qshareddatapointer.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API