Spec-Zone.ru › Qt 5.12

Класс 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 реализует потокобезопасный подсчет ссылок, гарантируя, что добавление 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, чья 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/qt-5.12/qshareddatapointer.html

Spec-Zone.ru

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