QSharedDataPointer Class
template <typename T> class QSharedDataPointerQSharedDataPointer クラスは、暗黙の共有オブジェクトへのポインタを表します。詳細...
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
クラスのソース・コードを見てみましょう。ヘッダー・ファイルでは、Employee
とEmployeeData
の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 のプライベート・サブクラスをパブリック・ファイルに含めない別のファイルに置くことで、ユーザーから隠します。この場合、通常はクラスEmployeeData
をemployee.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 に設定されただけなので、書き込み時にコピーが発生しないことに注意してください。
Employee
のconstメンバ関数では、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 がそれに割り当てられた後、e1
とe2
の両方が従業員 1001 の Albrecht Durer を参照しています。両方のEmployee
オブジェクトは、参照カウント 2 を持つEmployeeData
の同じインスタンスを指します。次に、e1.setName("Hans Holbein")
が呼び出され、従業員の名前が変更されるが、参照カウントが1より大きいため、名前が変更される前に書き込み時のコピーが実行される。ここで、e1
とe2
は異なる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も参照してください 。
メンバ関数ドキュメント
[noexcept]
QSharedDataPointer::QSharedDataPointer()
nullptr
をd ポインタとして初期化された 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 ポインタを o のd ポインタに設定し、共有データオブジェクトの参照カウントをインクリメントします。
[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 に設定し、ptr がnullptr
でない場合はptr の参照カウントをインクリメントします。古い共有データオブジェクトの参照カウントがデクリメントされ、参照カウントが0になった場合はオブジェクトが削除されます。
この関数は Qt 6.0 で導入されました。
[noexcept]
void QSharedDataPointer::swap(QSharedDataPointer<T> &other)
このインスタンスの共有データ・ポインタをother の共有データ・ポインタと交換します。
[noexcept, since 6.0]
T *QSharedDataPointer::take()
共有オブジェクトへのポインタを返し、これを nullptr
にリセットします(つまり、この関数はthisのd ポインタを 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ポインタを o のdポインタにセットし、共有データオブジェクトの参照カウントをインクリメントする。thisの古い共有データオブジェクトの参照カウントをデクリメントする。古い共有データ・オブジェクトの参照カウントが0になると、古い共有データ・オブジェクトは削除される。
関連する非会員
[noexcept]
bool operator!=(const QSharedDataPointer<T> &lhs, const QSharedDataPointer<T> &rhs)
lhs とrhs が同じd ポインタを持って いない場合、true
を返す。この関数はdetach() を呼び出さない。
[noexcept]
bool operator!=(const T *ptr, const QSharedDataPointer<T> &rhs)
rhs のd ポインタが ptr のd ポインタでない場合、true
を返す。この関数はdetach() を呼び出さない。
[noexcept]
bool operator==(const QSharedDataPointer<T> &lhs, const QSharedDataPointer<T> &rhs)
lhs とrhs のd ポインタが同じ場合はtrue
を返す。この関数はdetach() を呼び出さない。
[noexcept]
bool operator==(const T *ptr, const QSharedDataPointer<T> &rhs)
rhs のd ポインタが ptr の場合、true
を返す。この関数はdetach() を呼び出さない。
©2024 The Qt Company Ltd. 本書に含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。