Spec-Zone.ru › Qt

Класс QSharedDataPointer

шаблон <typename T> class QSharedDataPointer

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

Заголовок: #include <QSharedDataPointer>
CMake: find_package(Qt6 COMPONENTS Core REQUIRED) target_link_libraries(mytarget PRIVATE Qt6::Core)
qmake: QT += core
  • Список всех членов, включая унаследованные

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

Публичные типы

Type

Публичные функции

QSharedDataPointer(QSharedDataPointer<T> &&o)
QSharedDataPointer(const QSharedDataPointer<T> &o)
QSharedDataPointer(T *data, QAdoptSharedDataTag)
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()
T * get()
const T * get() const
void reset(T *ptr = nullptr)
void swap(QSharedDataPointer<T> &other)
T * take()
T * operator T *()
const T * operator const T *() const
bool operator!() const
T & operator*()
const T & operator*() const
T * operator->()
const T * operator->() const
QSharedDataPointer<T> & operator=(T *o)

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

T * clone()

Связанные нечлены

bool operator!=(const QSharedDataPointer<T> &lhs, const QSharedDataPointer<T> &rhs)
bool operator!=(const T *ptr, const QSharedDataPointer<T> &rhs)
bool operator==(const QSharedDataPointer<T> &lhs, const QSharedDataPointer<T> &rhs)
bool operator==(const T *ptr, const QSharedDataPointer<T> &rhs)

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

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.

В не-const членской функции 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 с модификатором const разыменование указателя 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() не вызывается в не-const функциях). В этом случае после e1.setName("Hans Holbein"), имя сотрудника было изменено, но e1 и e2 всё ещё ссылаются на один экземпляр EmployeeData, поэтому существует только один сотрудник с ID 1001.

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

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

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

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

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

QSharedDataPointer::Type

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

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

[since 5.2] QSharedDataPointer::QSharedDataPointer(QSharedDataPointer<T> &&o)

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

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

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

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

[since 6.0] QSharedDataPointer::QSharedDataPointer(T *data, QAdoptSharedDataTag)

Создаёт QSharedDataPointer с указателем d, установленным на data. Счётчик ссылок data не увеличивается; это можно использовать для принятия указателей, полученных из take().

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

См. также take().

QSharedDataPointer::QSharedDataPointer(T *data)

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

QSharedDataPointer::QSharedDataPointer()

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

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

const T *QSharedDataPointer::constData() const

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

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

T *QSharedDataPointer::data()

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

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

const T *QSharedDataPointer::data() const

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

void QSharedDataPointer::detach()

Если счётчик ссылок на объект общих данных больше 1, эта функция создаёт глубокую копию объекта общих данных и устанавливает указатель d этого объекта на копию.

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

[since 6.0] T *QSharedDataPointer::get()

То же, что и data(). Эта функция предоставляется для совместимости со STL.

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

[since 6.0] const T *QSharedDataPointer::get() const

То же, что и data(). Эта функция предоставляется для совместимости со STL.

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

[since 6.0] void QSharedDataPointer::reset(T *ptr = nullptr)

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

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

void QSharedDataPointer::swap(QSharedDataPointer<T> &other)

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

[since 6.0] T *QSharedDataPointer::take()

Возвращает указатель на общий объект и сбрасывает this в nullptr. (То есть, эта функция устанавливает указатель d для this в nullptr.)

Примечание: Счётчик ссылок возвращённого объекта не будет уменьшен. Эта функция может использоваться вместе с конструктором, принимающим объект QAdoptSharedDataTag, для передачи общего объекта данных без промежуточных атомарных операций.

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

T *QSharedDataPointer::operator T *()

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

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

const T *QSharedDataPointer::operator const T *() const

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

bool QSharedDataPointer::operator!() const

Возвращает true если указатель d для this равен nullptr.

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 для this в o и увеличивает счётчик ссылок o. Счётчик ссылок старого общего объекта данных для this уменьшается. Если счётчик ссылок старого общего объекта данных станет 0, старый общий объект данных удаляется.

Связанные нечлены

bool operator!=(const QSharedDataPointer<T> &lhs, const QSharedDataPointer<T> &rhs)

Возвращает true если lhs и rhs не имеют одинакового указателя d. Эта функция не вызывает detach().

bool operator!=(const T *ptr, const QSharedDataPointer<T> &rhs)

Возвращает true если указатель d для rhs не равен ptr. Указатель d. Эта функция не вызывает detach().

bool operator==(const QSharedDataPointer<T> &lhs, const QSharedDataPointer<T> &rhs)

Возвращает true если lhs и rhs имеют одинаковый указатель d. Эта функция не вызывает detach().

bool operator==(const T *ptr, const QSharedDataPointer<T> &rhs)

Возвращает true если указатель d для rhs равен ptr. Эта функция не вызывает detach().

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.2/qshareddatapointer.html

Spec-Zone.ru

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