Spec-Zone.ru › Qt 5.6

Класс QSharedDataPointer

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

Заголовок: #include <QSharedDataPointer>
qmake: QT += core
С момента: Qt 4.0
  • Список всех членов, включая унаследованные

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

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

typedef Type

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

QSharedDataPointer()
QSharedDataPointer(T *sharedData)
QSharedDataPointer(const QSharedDataPointer<T> &other)
QSharedDataPointer(QSharedDataPointer &&o)
~QSharedDataPointer()
const T * constData() const
T * data()
const T * data() const
void detach()
void swap(QSharedDataPointer &other)
operator 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> &other)
QSharedDataPointer & operator=(T *sharedData)
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 имеет конструктор по умолчанию, конструктор копирования и деструктор. Обычно в классе 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, чья 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 объекты. У них разные имена, но оба имеют идентификатор 1001, что, вероятно, не то, что вы хотите. Вы, конечно, можете просто продолжить с e1.setId(1002), если действительно хотите создать второго, уникального сотрудника, но если вы хотите только изменить имя сотрудника повсюду, рассмотрите использование явного совместного использования в классе Employee вместо неявного совместного использования.

Если вы объявите указатель d в классе Employee как QExplicitlySharedDataPointer<EmployeeData>, то будет использоваться явное совместное использование, и операции копирование при записи не будут выполняться автоматически (т.е. 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, инициализированный нулевым указателем d.

QSharedDataPointer::QSharedDataPointer(T *sharedData)

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

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

Устанавливает указатель d объекта this на указатель d в other и увеличивает счётчик ссылок на общий объект данных.

QSharedDataPointer::QSharedDataPointer(QSharedDataPointer &&o)

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

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

QSharedDataPointer::~QSharedDataPointer()

Уменьшает счётчик ссылок на общий объект данных. Если счётчик ссылок станет равным 0, общий объект данных удаляется. Тогда разрушается this.

[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 объекта this на копию.

Эта функция вызывается автоматически неконстантными функциями-членами QSharedDataPointer, если требуется копирование при записи. Вам не нужно вызывать её самостоятельно.

void QSharedDataPointer::swap(QSharedDataPointer &other)

Меняет указатель на общий объект данных данного экземпляра с указателем на общий объект данных в other.

QSharedDataPointer::operator T *()

Возвращает указатель на общий объект данных. Эта функция вызывает detach().

См. также data() и constData().

QSharedDataPointer::operator const T *() const

Возвращает указатель на общий объект данных. Эта функция не вызывает detach().

bool QSharedDataPointer::operator!() const

Возвращает true, если указатель d объекта this равен null.

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

Устанавливает указатель d объекта this на указатель d объекта other и увеличивает счётчик ссылок на общий объект данных. Счётчик ссылок на старый общий объект данных this уменьшается. Если счётчик ссылок на старый общий объект данных становится 0, старый общий объект данных удаляется.

QSharedDataPointer &QSharedDataPointer::operator=(T *sharedData)

Устанавливает указатель d объекта this на sharedData и увеличивает счётчик ссылок sharedData. Счётчик ссылок на старый общий объект данных this уменьшается. Если счётчик ссылок на старый общий объект данных становится 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.6/qshareddatapointer.html

Spec-Zone.ru

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