QSharedDataPointer Class

template <typename T> class QSharedDataPointer

Die Klasse QSharedDataPointer repräsentiert einen Zeiger auf ein implizit freigegebenes Objekt. Mehr...

Kopfzeile: #include <QSharedDataPointer>
CMake: find_package(Qt6 REQUIRED COMPONENTS Core)
target_link_libraries(mytarget PRIVATE Qt6::Core)
qmake: QT += core

Hinweis: Alle Funktionen in dieser Klasse sind reentrant.

Öffentliche Typen

Öffentliche Funktionen

QSharedDataPointer()
QSharedDataPointer(T *data)
(since 6.0) QSharedDataPointer(T *data, QAdoptSharedDataTag)
QSharedDataPointer(const QSharedDataPointer<T> &o)
QSharedDataPointer(QSharedDataPointer<T> &&o)
~QSharedDataPointer()
const T *constData() const
T *data()
const T *data() const
void detach()
(since 6.0) T *get()
(since 6.0) const T *get() const
(since 6.0) void reset(T *ptr = nullptr)
void swap(QSharedDataPointer<T> &other)
(since 6.0) 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=(QSharedDataPointer<T> &&other)
QSharedDataPointer<T> &operator=(T *o)
QSharedDataPointer<T> &operator=(const QSharedDataPointer<T> &o)

Geschützte Funktionen

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)

Detaillierte Beschreibung

QSharedDataPointer<T> macht das Schreiben eigener , implizit gemeinsam genutzter Klassen einfach. QSharedDataPointer implementiert Thread-sichere Referenzzählung und stellt sicher, dass das Hinzufügen von QSharedDataPointers zu Ihren reentranten Klassen diese nicht nicht-reentrant macht.

Implizites Sharing wird von vielen Qt-Klassen verwendet, um die Geschwindigkeit und Speichereffizienz von Zeigern mit der Benutzerfreundlichkeit von Klassen zu kombinieren. Siehe die Seite Shared Classes für weitere Informationen.

Angenommen, Sie möchten eine Employee Klasse implizit gemeinsam nutzen. Die Prozedur ist:

  • Definieren Sie die Klasse Employee so, dass sie ein einziges Datenelement vom Typ QSharedDataPointer<EmployeeData> enthält.
  • Definieren Sie die von QSharedData abgeleitete Klasse EmployeeData so, dass sie alle Datenelemente enthält, die Sie normalerweise in der Klasse Employee untergebracht hätten.

Um dies in der Praxis zu zeigen, betrachten wir den Quellcode der implizit gemeinsam genutzten Klasse Employee. In der Header-Datei definieren wir die beiden Klassen Employee und 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;
};

Beachten Sie in der Klasse Employee das einzige Datenelement, einen d-Zeiger vom Typ QSharedDataPointer<EmployeeData>. Alle Zugriffe auf Mitarbeiterdaten müssen über den d-Zeiger von operator->() erfolgen. Bei Schreibzugriffen ruft operator->() automatisch detach() auf, das eine Kopie des gemeinsamen Datenobjekts erstellt, wenn die Referenzanzahl des gemeinsamen Datenobjekts größer als 1 ist. Dadurch wird sichergestellt, dass Schreibzugriffe auf ein Employee Objekt keine anderen Employee Objekte beeinflussen, die dasselbe EmployeeData Objekt teilen.

Die Klasse EmployeeData erbt QSharedData, die den Referenzzähler hinter den Kulissen bereitstellt. EmployeeData hat einen Standardkonstruktor, einen Kopierkonstruktor und einen Destruktor. Normalerweise sind triviale Implementierungen dieser Funktionen alles, was in der Datenklasse für eine implizit gemeinsam genutzte Klasse benötigt wird.

Die Implementierung der beiden Konstruktoren für die Klasse Employee ist ebenfalls einfach. Beide erzeugen eine neue Instanz von EmployeeData und weisen sie dem Zeiger d zu.

    Employee() { d = new EmployeeData; }

    Employee(int id, const QString &name) {
        d = new EmployeeData;
        setId(id);
        setName(name);
    }

Beachten Sie, dass die Klasse Employee auch einen trivialen Kopierkonstruktor definiert hat, der in diesem Fall nicht unbedingt erforderlich ist.

    Employee(const Employee &other)
          : d (other.d)
    {
    }

Der Kopierkonstruktor ist hier nicht unbedingt erforderlich, da die Klasse EmployeeData in derselben Datei wie die Klasse Employee (employee.h) enthalten ist. Es ist jedoch untypisch, die private Unterklasse von QSharedData in dieselbe Datei aufzunehmen wie die öffentliche Klasse, die den QSharedDataPointer enthält. Normalerweise ist die Idee, die private Unterklasse von QSharedData vor dem Benutzer zu verbergen, indem man sie in eine separate Datei aufnimmt, die nicht in die öffentliche Datei aufgenommen wird. In diesem Fall würden wir normalerweise die Klasse EmployeeData in einer separaten Datei ablegen, die nicht in employee.h enthalten ist. Stattdessen würden wir die private Unterklasse EmployeeData einfach in employee.h auf diese Weise vordeklarieren:

    class EmployeeData;

Hätten wir es hier so gemacht, wäre der gezeigte Kopierkonstruktor erforderlich. Da der Kopierkonstruktor trivial ist, können Sie ihn auch einfach immer einbinden.

Hinter den Kulissen erhöht QSharedDataPointer automatisch die Referenzanzahl, wenn ein Employee Objekt kopiert, zugewiesen oder als Parameter übergeben wird. Die Anzahl der Referenzen wird immer dann verringert, wenn ein Employee Objekt gelöscht wird oder den Gültigkeitsbereich verlässt. Das freigegebene EmployeeData Objekt wird automatisch gelöscht, wenn der Referenzzähler 0 erreicht.

In einer nicht-konstanten Mitgliedsfunktion von Employee ruft QSharedDataPointer automatisch detach() auf, wenn der Zeiger d dereferenziert wird, um sicherzustellen, dass die Funktion mit ihrer eigenen Kopie der Daten arbeitet.

    void setId(int id) { d->id = id; }

    void setName(const QString &name) { d->name = name; }

Beachten Sie, dass, wenn detach() aufgrund mehrerer Dereferenzierungen des d-Zeigers mehr als einmal in einer Mitgliedsfunktion aufgerufen wird, detach(), wenn überhaupt, nur beim ersten Aufruf eine Kopie der gemeinsam genutzten Daten erstellt, da beim zweiten und den folgenden Aufrufen von detach() der Referenzzähler wieder 1 sein wird.

Beachten Sie jedoch, dass im zweiten Employee -Konstruktor, der eine Mitarbeiter-ID und einen Namen annimmt, sowohl setId() als auch setName() aufgerufen werden, die jedoch keine Kopie beim Schreiben verursachen, da die Referenzanzahl für das neu konstruierte EmployeeData -Objekt gerade auf 1 gesetzt wurde.

In den const-Mitgliedsfunktionen von Employee führt die Dereferenzierung des Zeigers d nicht zum Aufruf von detach().

    int id() const { return d->id; }

    QString name() const { return d->name; }

Beachten Sie, dass es nicht notwendig ist, einen Kopierkonstruktor oder einen Zuweisungsoperator für die Klasse Employee zu implementieren, da der Kopierkonstruktor und der Zuweisungsoperator, die vom C++-Compiler bereitgestellt werden, die erforderlichen flachen Kopien Member für Member durchführen. Der einzige zu kopierende Member ist der Zeiger d, der ein QSharedDataPointer ist, dessen operator=() lediglich die Referenzanzahl des gemeinsam genutzten EmployeeData Objekts erhöht.

Implizites vs. explizites Sharing

Implizites Sharing ist für die Klasse Employee möglicherweise nicht geeignet. Betrachten Sie ein einfaches Beispiel, das zwei Instanzen der implizit gemeinsam genutzten Klasse Employee erzeugt.

#include "employee.h"

int main()
{
    Employee e1(1001, "Albrecht Durer");
    Employee e2 = e1;
    e1.setName("Hans Holbein");
}

Nachdem der zweite Mitarbeiter e2 erstellt und ihm e1 zugewiesen wurde, verweisen sowohl e1 als auch e2 auf Albrecht Durer, Mitarbeiter 1001. Beide Employee Objekte zeigen auf dieselbe Instanz von EmployeeData, die die Referenzanzahl 2 hat. Dann wird e1.setName("Hans Holbein") aufgerufen, um den Namen des Angestellten zu ändern, aber da die Referenzanzahl größer als 1 ist, wird eine Kopie beim Schreiben durchgeführt, bevor der Name geändert wird. Nun verweisen e1 und e2 auf verschiedene EmployeeData Objekte. Sie haben unterschiedliche Namen, aber beide haben die ID 1001, was wahrscheinlich nicht das ist, was Sie wollen. Sie können natürlich einfach mit e1.setId(1002) weitermachen, wenn Sie wirklich einen zweiten, eindeutigen Angestellten schaffen wollen, aber wenn Sie nur den Namen des Angestellten überall ändern wollen, sollten Sie explicit sharing in der Klasse Employee anstelle der impliziten Freigabe verwenden.

Wenn Sie den d-Zeiger in der Klasse Employee als QExplicitlySharedDataPointer<EmployeeData> deklarieren, wird die explizite Freigabe verwendet, und Kopiervorgänge bei Schreibvorgängen werden nicht automatisch ausgeführt (d. h. detach() wird nicht in Nicht-Konstanten-Funktionen aufgerufen). In diesem Fall wurde nach e1.setName("Hans Holbein") der Name des Mitarbeiters geändert, aber sowohl e1 als auch e2 verweisen immer noch auf dieselbe Instanz von EmployeeData, so dass es nur einen Mitarbeiter mit der ID 1001 gibt.

In der Dokumentation der Mitgliedsfunktionen bezieht sich d pointer immer auf den internen Zeiger auf das gemeinsame Datenobjekt.

Optimieren der Leistung für die Verwendung in Qt Containern

Sie sollten in Erwägung ziehen, Ihre implizit gemeinsam genutzte Klasse mit dem Q_DECLARE_TYPEINFO() Makro als beweglichen Typ zu markieren, wenn sie der obigen Klasse Employee ähnelt und einen QSharedDataPointer oder QExplicitlySharedDataPointer als einziges Mitglied verwendet. Dies kann die Leistung und Speichereffizienz bei der Verwendung von Qt's Container-Klassen verbessern.

Siehe auch QSharedData, QExplicitlySharedDataPointer, QScopedPointer, und QSharedPointer.

Dokumentation der Membertypen

QSharedDataPointer::Type

Dies ist der Typ des gemeinsamen Datenobjekts. Der Zeiger d zeigt auf ein Objekt dieses Typs.

Dokumentation der Mitgliedsfunktionen

[noexcept] QSharedDataPointer::QSharedDataPointer()

Konstruiert einen QSharedDataPointer, initialisiert mit nullptr als d-Zeiger.

[explicit noexcept] QSharedDataPointer::QSharedDataPointer(T *data)

Konstruiert einen QSharedDataPointer mit dem Zeiger d, der auf data gesetzt ist, und erhöht die Referenzanzahl von data.

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

Konstruiert einen QSharedDataPointer mit dem Zeiger d, der auf data gesetzt ist. Der Referenzzähler von data wird nicht inkrementiert; dies kann verwendet werden, um Zeiger zu übernehmen, die von take() erhalten wurden.

Diese Funktion wurde in Qt 6.0 eingeführt.

Siehe auch take().

[noexcept] QSharedDataPointer::QSharedDataPointer(const QSharedDataPointer<T> &o)

Setzt den d-Zeiger von this auf den d-Zeiger in o und erhöht die Referenzanzahl des gemeinsamen Datenobjekts.

[noexcept] QSharedDataPointer::QSharedDataPointer(QSharedDataPointer<T> &&o)

Move-konstruiert eine QSharedDataPointer-Instanz, die auf das gleiche Objekt zeigt, auf das o gezeigt hat.

QSharedDataPointer::~QSharedDataPointer()

Verringert die Referenzanzahl des gemeinsamen Datenobjekts. Wenn der Referenzzähler 0 wird, wird das gemeinsame Datenobjekt gelöscht. Anschließend wird es zerstört.

[protected] T *QSharedDataPointer::clone()

Erstellt eine tiefe Kopie der aktuellen Daten und gibt sie zurück. Diese Funktion wird von detach() aufgerufen, wenn die Referenzanzahl größer als 1 ist, um die neue Kopie zu erstellen. Diese Funktion verwendet den Operator new und ruft den Kopierkonstruktor des Typs T auf.

Diese Funktion wird zur Verfügung gestellt, damit Sie "virtuelle Kopierkonstruktoren" für Ihre eigenen Typen unterstützen können. Um dies zu tun, sollten Sie eine Template-Spezialisierung dieser Funktion für Ihren eigenen Typ deklarieren, wie im folgenden Beispiel:

    template<>
    EmployeeData *QSharedDataPointer<EmployeeData>::clone()
    {
        return d->clone();
    }

Im obigen Beispiel ruft die Template-Spezialisierung für die Funktion clone() die virtuelle Funktion EmployeeData::clone() auf. Eine von EmployeeData abgeleitete Klasse könnte diese Funktion außer Kraft setzen und den richtigen polymorphen Typ zurückgeben.

[noexcept] const T *QSharedDataPointer::constData() const

Gibt einen Konstantenzeiger auf das gemeinsame Datenobjekt zurück. Diese Funktion ruft nicht detach() auf.

Siehe auch data().

T *QSharedDataPointer::data()

Gibt einen Zeiger auf das gemeinsame Datenobjekt zurück. Diese Funktion ruft detach() auf.

Siehe auch constData().

[noexcept] const T *QSharedDataPointer::data() const

Gibt einen Zeiger auf das gemeinsame Datenobjekt zurück. Diese Funktion ruft nicht detach() auf.

void QSharedDataPointer::detach()

Wenn die Referenzanzahl des gemeinsamen Datenobjekts größer als 1 ist, erstellt diese Funktion eine tiefe Kopie des gemeinsamen Datenobjekts und setzt den d-Zeiger dieses Objekts auf die Kopie.

Diese Funktion wird automatisch von nicht-konstanten Mitgliedsfunktionen von QSharedDataPointer aufgerufen, wenn eine Kopie beim Schreiben erforderlich ist. Sie brauchen sie nicht selbst aufzurufen.

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

Dasselbe wie data(). Diese Funktion wird aus Gründen der STL-Kompatibilität bereitgestellt.

Diese Funktion wurde in Qt 6.0 eingeführt.

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

Dasselbe wie data(). Diese Funktion wird aus Gründen der STL-Kompatibilität bereitgestellt.

Diese Funktion wurde in Qt 6.0 eingeführt.

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

Setzt den d-Zeiger von this auf ptr und erhöht den Referenzzähler von ptr, wenn ptr nicht nullptr ist. Der Referenzzähler des alten gemeinsamen Datenobjekts wird dekrementiert, und das Objekt wird gelöscht, wenn der Referenzzähler 0 erreicht.

Diese Funktion wurde in Qt 6.0 eingeführt.

[noexcept] void QSharedDataPointer::swap(QSharedDataPointer<T> &other)

Tauscht diesen gemeinsamen Datenzeiger mit other aus. Dieser Vorgang ist sehr schnell und schlägt nie fehl.

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

Gibt einen Zeiger auf das gemeinsam genutzte Objekt zurück und setzt dieses auf nullptr zurück. (Das heißt, diese Funktion setzt den d-Zeiger von this auf nullptr.)

Hinweis: Der Referenzzähler des zurückgegebenen Objekts wird nicht dekrementiert. Diese Funktion kann zusammen mit dem Konstruktor verwendet werden, der ein QAdoptSharedDataTag Tag-Objekt annimmt, um das gemeinsame Datenobjekt ohne zwischengeschaltete atomare Operationen zu übertragen.

Diese Funktion wurde in Qt 6.0 eingeführt.

T *QSharedDataPointer::operator T *()

Gibt einen Zeiger auf das gemeinsame Datenobjekt zurück. Diese Funktion ruft detach() auf.

Siehe auch data() und constData().

[noexcept] const T *QSharedDataPointer::operator const T *() const

Gibt einen Zeiger auf das gemeinsame Datenobjekt zurück. Diese Funktion ruft nicht detach() auf.

[noexcept] bool QSharedDataPointer::operator!() const

Gibt true zurück, wenn der d-Zeiger von this nullptr ist.

T &QSharedDataPointer::operator*()

Ermöglicht den Zugriff auf die Mitglieder des gemeinsamen Datenobjekts. Diese Funktion ruft detach() auf.

const T &QSharedDataPointer::operator*() const

Bietet konstanten Zugriff auf die Mitglieder des gemeinsamen Datenobjekts. Diese Funktion ruft nicht detach() auf.

T *QSharedDataPointer::operator->()

Ermöglicht den Zugriff auf die Mitglieder des gemeinsamen Datenobjekts. Diese Funktion ruft detach() auf.

[noexcept] const T *QSharedDataPointer::operator->() const

Bietet konstanten Zugriff auf die Mitglieder des gemeinsamen Datenobjekts. Diese Funktion ruft nicht detach() auf.

[noexcept] QSharedDataPointer<T> &QSharedDataPointer::operator=(QSharedDataPointer<T> &&other)

Verschieben - weist other dieser QSharedDataPointer Instanz zu.

[noexcept] QSharedDataPointer<T> &QSharedDataPointer::operator=(T *o)

Setzt den d-Zeiger von this auf o und erhöht den Referenzzähler von o. Der Referenzzähler des alten gemeinsamen Datenobjekts von this wird dekrementiert. Wenn der Referenzzähler des alten gemeinsamen Datenobjekts 0 wird, wird das alte gemeinsame Datenobjekt gelöscht.

[noexcept] QSharedDataPointer<T> &QSharedDataPointer::operator=(const QSharedDataPointer<T> &o)

Setzt den d-Zeiger von this auf den d-Zeiger von o und erhöht die Referenzanzahl des gemeinsamen Datenobjekts. Der Referenzzähler des alten gemeinsamen Datenobjekts von this wird dekrementiert. Wenn der Referenzzähler des alten gemeinsamen Datenobjekts 0 wird, wird das alte gemeinsame Datenobjekt gelöscht.

Verwandte Nicht-Mitglieder

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

Gibt true zurück, wenn lhs und rhs nicht denselben d-Zeiger haben. Diese Funktion ruft nicht detach() auf.

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

Gibt true zurück, wenn der d-Zeiger von rhs nicht ptr ist. d-Zeiger. Diese Funktion ruft nicht detach() auf.

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

Gibt true zurück, wenn lhs und rhs denselben d-Zeiger haben. Diese Funktion ruft nicht detach() auf.

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

Gibt true zurück, wenn der d-Zeiger von rhs ptr ist. Diese Funktion ruft nicht detach() auf.

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.