QSharedDataPointer Class

template <typename T> class QSharedDataPointer

QSharedDataPointer クラスは、暗黙の共有オブジェクトへのポインタを表します。詳細...

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

注:このクラスの関数はすべてリエントラントです。

パブリック型

パブリック関数

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)

保護された機能

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 はスレッドセーフな参照カウントを実装しており、リエントラントなクラスに QSharedDataPointer を追加してもリエントラントでなくなることはありません。

暗黙的な共有は、ポインタの速度とメモリ効率とクラスの使いやすさを組み合わせるために、多くの Qt クラスで使用されています。詳細は共有クラスのページを参照してください。

Employee クラスを暗黙の共有にしたいとします。その手順は

  • QSharedDataPointer<EmployeeData> 型のデータ・メンバを1つ持つようにEmployee クラスを定義します。
  • QSharedData から派生したEmployeeData クラスを定義し、通常Employee クラスに入れるはずのデータ・メンバをすべて入れます。

これを実際に示すために、暗黙的に共有されているEmployee クラスのソース・コードを見てみましょう。ヘッダー・ファイルでは、EmployeeEmployeeData の2つのクラスを定義します。

#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 では、単一のデータ・メンバ、QSharedDataPointer<EmployeeData> 型のd ポインタに注目してください。社員データへのアクセスはすべて、dポインターの operator->() を経由しなければならない。書き込みアクセスの場合、operator->() は自動的にdetach() を呼び出します。共有データ・オブジェクトの参照カウントが1より大きい場合、共有データ・オブジェクトのコピーが作成されます。これにより、1つのEmployee オブジェクトへの書き込みが、同じEmployeeData オブジェクトを共有する他のEmployee オブジェクトに影響しないことが保証されます。

クラスEmployeeData は、QSharedData を継承しています。 は、舞台裏の参照カウンターを提供します。EmployeeData は、デフォルトのコンストラクタ、コピーコンストラクタ、デストラクタを持ちます。通常、暗黙的に共有されるクラスのデータ・クラスで必要なのは、これらの些細な実装だけです。

クラスEmployee の2つのコンストラクタの実装も簡単です。どちらも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 のプライベート・サブクラスをパブリック・ファイルに含めない別のファイルに置くことで、ユーザーから隠します。この場合、通常はクラスEmployeeDataemployee.h に含まれない別のファイルに置きます。その代わりに、employee.h でプライベート・サブクラスEmployeeData を事前宣言します:

    class EmployeeData;

もしこのようにした場合、コピー・コンストラクタが必要になる。コピー・コンストラクタは些細なものなので、常に含めるようにした方がよいでしょう。

舞台裏では、QSharedDataPointerは、Employee オブジェクトがコピーされたり、代入されたり、パラメータとして渡されたりするたびに、参照カウントを自動的にインクリメントします。QSharedDataPointerは、Employee オブジェクトが削除されたり、スコープ外になるたびに、参照カウントをデクリメントします。参照カウントが 0 になると、共有されたEmployeeData オブジェクトは自動的に削除されます。

Employee の非 const メンバ関数では、d ポインタが再参照されるたびに、QSharedDataPointer は自動的にdetach() を呼び出し、関数がデータの独自のコピーで動作するようにします。

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

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

detachd ポインタの複数回の再参照により、メンバ関数内でdetach() が複数回呼び出された場合、detach() が共有データのコピーを作成するのは、それが最初に呼び出されたときだけである。

しかし、2 番目のEmployee コンストラクタでは、従業員 ID と名前を取り、setId() と setName() の両方が呼び出されますが、新しく構築されたEmployeeData オブジェクトの参照カウントが 1 に設定されただけなので、書き込み時にコピーが発生しないことに注意してください。

Employeeconstメンバ関数では、d ポインタを再参照してもdetach() は呼び出されない

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

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

C++コンパイラが提供するコピー・コンストラクタと代入演算子は、必要なメンバごとの浅いコピーを行うので、Employee クラスにコピー・コンストラクタや代入演算子を実装する必要はないことに注意してください。コピーする唯一のメンバーはdポインターで、これはQSharedDataPointerであり、そのoperator=() 、共有EmployeeData オブジェクトの参照カウントをインクリメントするだけです。

暗黙的共有と明示的共有

Employee 、暗黙的な共有は適切ではないかもしれません。暗黙的に共有されるEmployee クラスのインスタンスを2つ作成する簡単な例を考えてみましょう。

#include "employee.h"

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

2番目の従業員 e2 が作成され、e1 がそれに割り当てられた後、e1e2 の両方が従業員 1001 の Albrecht Durer を参照しています。両方のEmployee オブジェクトは、参照カウント 2 を持つEmployeeData の同じインスタンスを指します。次に、e1.setName("Hans Holbein") が呼び出され、従業員の名前が変更されるが、参照カウントが1より大きいため、名前が変更される前に書き込み時のコピーが実行される。ここで、e1e2 は異なるEmployeeData オブジェクトを指している。名前は違いますが、どちらもIDは1001です。もちろん、本当に2人目のユニークな従業員を作成するのであれば、e1.setId(1002) をそのまま続けることもできますが、従業員の名前をどこでも変更したいだけであれば、暗黙的な共有ではなく、Employee クラスでexplicit sharing を使用することを検討してください。

Employee クラスのd ポインタを QExplicitlySharedDataPointer<EmployeeData> と宣言した場合、明示的共有が使用され、書き込み操作時のコピーは自動的には実行されません(つまり、detach() は非 const 関数では呼び出されません)。この場合、e1.setName("Hans Holbein") の後、従業員の名前は変更されましたが、e1 と e2 の両方がEmployeeData の同じインスタンスを参照しているため、ID 1001 を持つ従業員は 1 人だけです。

メンバ関数のドキュメントでは、dポインタは常に共有データ・オブジェクトの内部ポインタを指します。

Qt コンテナでの使用におけるパフォーマンスの最適化

暗黙の共有クラスが上記のEmployee クラスに似ていて、唯一のメンバとして QSharedDataPointer またはQExplicitlySharedDataPointer を使用している場合は、Q_DECLARE_TYPEINFO() マクロを使用して移動可能な型としてマークすることを検討する必要があります。これにより、Qt のコンテナクラスを使用する際のパフォーマンスとメモリ効率が向上します。

QSharedData,QExplicitlySharedDataPointer,QScopedPointer,QSharedPointerも参照してください

メンバ型ドキュメント

QSharedDataPointer::Type

共有データ・オブジェクトの型。dポインターはこの型のオブジェクトを指す。

メンバ関数ドキュメント

[noexcept] QSharedDataPointer::QSharedDataPointer()

nullptrd ポインタとして初期化された QSharedDataPointer を構築します。

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

d ポインタが data に設定された QSharedDataPointer を構築し、data の参照カウントをインクリメントします。

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

d ポインタが data に設定された QSharedDataPointer を構築します。data の参照カウンタはインクリメントされません。これは、take() から取得したポインタを採用するために使用できます。

この関数は Qt 6.0 で導入されました。

take()も参照してください

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

この関数の d ポインタを od ポインタに設定し、共有データオブジェクトの参照カウントをインクリメントします。

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

Move-QSharedDataPointerインスタンスを構築し、o が指していたのと同じオブジェクトを指すようにする。

QSharedDataPointer::~QSharedDataPointer()

共有データ・オブジェクトの参照カウントを減らします。参照カウントが0になると、共有データ・オブジェクトが削除されます。その後、これは破棄されます。

[protected] T *QSharedDataPointer::clone()

現在のデータのディープ・コピーを作成して返します。この関数は、新しいコピーを作成するために、参照カウントが 1 より大きいときにdetach() によって呼び出される。この関数はnew 演算子を使用し、T 型のコピー・コンストラクタを呼び出します。

この関数は、独自の型の「仮想コピー・コンストラクタ」をサポートするために用意されています。そのためには、以下の例のように、あなた自身の型に対してこの関数のテンプレート特殊化を宣言する必要があります:

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

上記の例では、clone() 関数のテンプレート特化はEmployeeData::clone()仮想関数を呼び出します。EmployeeData から派生したクラスは、この関数をオーバーライドして、適切な多相型を返すことができます。

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

共有データ・オブジェクトへの const ポインタを返します。この関数は、detach() を呼び出しません

data()も参照

T *QSharedDataPointer::data()

共有データ・オブジェクトへのポインタを返します。この関数はdetach() を呼び出します。

constData()も参照

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

共有データ・オブジェクトへのポインタを返します。この関数はdetach() を呼び出さない

void QSharedDataPointer::detach()

共有データ・オブジェクトの参照カウントが1より大きい場合、この関数は共有データ・オブジェクトのディープ・コピーを作成し、そのコピーにdポインタを設定します。

この関数は、書き込み時のコピーが必要な場合、QSharedDataPointer の非 const メンバ関数によって自動的に呼び出される。自分で呼び出す必要はありません。

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

data() と同じ。この関数は STL との互換性のために提供されています。

この関数は Qt 6.0 で導入されました。

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

data() と同じ。この関数は STL との互換性のために提供されています。

この関数は Qt 6.0 で導入されました。

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

この関数の d ポインタを ptr に設定し、ptrnullptr でない場合はptr の参照カウントをインクリメントします。古い共有データオブジェクトの参照カウントがデクリメントされ、参照カウントが0になった場合はオブジェクトが削除されます。

この関数は Qt 6.0 で導入されました。

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

このインスタンスの共有データ・ポインタをother の共有データ・ポインタと交換します。

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

共有オブジェクトへのポインタを返し、これを nullptr にリセットします(つまり、この関数はthisd ポインタを nullptr に設定します)。

注意: 返されたオブジェクトの参照カウントはデクリメントされない。この関数は、QAdoptSharedDataTag タグ・オブジェクトを受け取るコンストラクタと一緒に使用することで、アトミック操作を介さずに共有データ・オブジェクトを転送することができます。

この関数は Qt 6.0 で導入されました。

T *QSharedDataPointer::operator T *()

共有データ・オブジェクトへのポインタを返します。この関数はdetach() を呼び出します。

data() およびconstData()も参照してください

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

共有データ・オブジェクトへのポインタを返します。この関数はdetach() を呼び出さない

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

この関数の d ポインタが nullptr の場合、true を返します。

T &QSharedDataPointer::operator*()

共有データ・オブジェクトのメンバにアクセスできるようにします。この関数はdetach() を呼び出します。

const T &QSharedDataPointer::operator*() const

共有データ・オブジェクトのメンバへの const アクセスを提供します。この関数はdetach() を呼び出さない

T *QSharedDataPointer::operator->()

共有データ・オブジェクトのメンバへのアクセスを提供します。この関数はdetach() を呼び出します。

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

共有データ・オブジェクトのメンバへの const アクセスを提供します。この関数はdetach() を呼び出さない

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

Move:other をこのQSharedDataPointer インスタンスに割り当てます。

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

このインスタンスの d ポインタを o に設定し、o の参照カウントをインクリメントします。thisの古い共有データ・オブジェクトの参照カウントがデクリメントされる。古い共有データ・オブジェクトの参照カウントが0になったら、古い共有データ・オブジェクトを削除する。

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

thisの dポインタを odポインタにセットし、共有データオブジェクトの参照カウントをインクリメントする。thisの古い共有データオブジェクトの参照カウントをデクリメントする。古い共有データ・オブジェクトの参照カウントが0になると、古い共有データ・オブジェクトは削除される。

関連する非会員

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

lhsrhs が同じd ポインタを持って いない場合、true を返す。この関数はdetach() を呼び出さない

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

rhsd ポインタが ptrd ポインタない場合、true を返す。この関数はdetach() を呼び出さない

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

lhsrhsd ポインタが同じ場合はtrue を返す。この関数はdetach() を呼び出さない

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

rhsd ポインタが ptr の場合、true を返す。この関数はdetach() を呼び出さない

©2024 The Qt Company Ltd. 本書に含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。