Spec-Zone.ru › Qt 5.13

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

Реализация двух конструкторов для класса 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(), но они не вызывают копирование при записи, так как счётчик ссылок для только что созданного объекта 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

Вы должны рассмотреть возможность маркировки вашего класса с неявным совместным использованием как перемещаемого типа, используя макрос Q_DECLARE_TYPEINFO(), если он похож на класс Employee выше и использует QSharedDataPointer или QExplicitlySharedDataPointer в качестве единственного члена. Это может улучшить производительность и эффективность использования памяти при использовании контейнерных классов 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 и this не имеют одинаковый указатель 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.13/qshareddatapointer.html

Spec-Zone.ru

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