弱いポインタ はオブジェクトに対する弱い参照を格納します。弱いポインタは 共有のポインタ や 共有の参照 とは異なり、参照するオブジェクトの破棄を防止しません。
弱いポインタが参照するオブジェクトにアクセスする前に、Pin
関数を使用して共有のポインタを作成する必要があります。これにより、使用されているオブジェクトが削除されず存続することが保証されます。弱いポインタがオブジェクトを参照しているかどうかをのみを確定する必要がある場合は、弱いポインタを`nullptr と比較するか、弱いポインタに対して`IsValid
を呼び出すことができます。
弱いポインタの使用は、目的を示すうえで役立ちます。つまり、弱いポインタは、参照されているオブジェクトをそのオブジェクトを所有することなく監視して、その存続期間を制御しないことを示します。
宣言、初期化、および代入
空の弱いポインタを作成したり、共有の参照、共有のポインタ、または別の弱いポインタから弱いポインタを作成することができます。
// 新しいデータ オブジェクトを割り当て、それへの強い参照を作成します。
TSharedRef<FMyObjectType> ObjectOwner = MakeShared<FMyObjectType>();
// 新しいデータ オブジェクトへの弱いポインタを作成します。
TWeakPtr<FMyObjectType> ObjectObserver(ObjectOwner);
弱いポインタはオブジェクトの破棄を防止しません。たとえば、ObjectOwner
をリセットすると、ObjectObserver
が依然としてスコープ内であるかどうかにかかわらずオブジェクトは破棄されます。
// ObjectOwner がそのオブジェクトの唯一の所有者であったと仮定すると、ObjectOwner がそのオブジェクトの参照を停止すると、そのオブジェクトは破棄されます。
ObjectOwner.Reset();
// Pin() が生成する共有のポインタは、ObjectOwner が Null オブジェクトを参照しているため Null になります。bool として扱われる場合、空の共有ポインタは false に評価されます。
if (ObjectObserver.Pin())
{
// このコードは、ObjectOwner がオブジェクトの唯一の所有者でなかった場合にのみ実行されます。
check(false);
}
弱いポインタは、有効なオブジェクトを参照しているかどうかにかかわらず、共有のポインタ同様、安全にコピーすることができます。
TWeakPtr<FMyObjectType> AnotherObjectObserver = ObjectObserver;
弱いポインタは使用し終えたらリセットできます。
// 弱いポインタを nullptr に設定することでリセットすることができます。
ObjectObserver = nullptr;
// Reset 関数を使うこともできます。
AnotherObjectObserver.Reset();
共有のポインタへの変換
Pin
関数は弱いポインタのオブジェクトへの共有のポインタを作成します。共有のポインタがスコープ内にあり、オブジェクトを参照している間、そのオブジェクトは有効です。また、共有のポインタ (Pin
関数が返す共有のポインタを含む) は、 true
が有効なオブジェクトであれば、条件式内で bool
型と評価される場合があります。以下のコード パターンは、弱いポインタが有効なオブジェクトを参照しているかどうかを確認して、参照していれば少なくとも (Pin
関数によって生成される) 共有のポインタがスコープ外になるか明示的にクリアされるまで有効であり続けることを保証します。
// 弱いポインタから共有のポインタを取得し、それが有効なオブジェクトを参照していることを確認します。
if (TSharedPtr<FMyObjectType> LockedObserver = ObjectObserver.Pin())
{
// 共有のポインタはこのスコープ内でのみ有効です。
// オブジェクトの存在が確認されており、共有のポインタは削除を防止します。
LockedObserver->SomeFunction();
}
逆参照とアクセス
弱いポインタのオブジェクトにアクセスするには、まずその弱いポインタを Pin
関数で共有のポインタに昇格させます。これにより、共有のポインタまたは弱いポインタ上で Get
関数を経由して該当オブジェクトにアクセスできるようになります。この方法では、オブジェクトは使用中有効であり続けることが保証されます。
参照サイクルの中断
2 つ以上のオブジェクトがスマートポインタを使用して相互に強い参照であり続ける場合は常に参照サイクルが存在します。このような場合、オブジェクトは常に他方のオブジェクトから参照されており、相互に削除を防止するため、一方が存在する限りどちらも削除できません。参照サイクルのどちらのオブジェクトにも外部からの参照がなければ、実質にリークします。弱いポインタは、参照するオブジェクトを保護しないため、このような参照サイクルを中断することができます。弱いポインタは、所有権を要求することなくオブジェクトを参照して、存続期間を延長できる可能性がある場合に使用します。
使用上の注意
弱いポインタはデータ オブジェクトの継続的な存在を保証する必要がない場合に役立ちますが、まさにこの特性が危険になる場合があります。弱いポインタの使用時に、次のような状態は注意が必要です。
Sets または Maps でのキーの使用。弱いポインタはいつでも無効になる可能性がありますが、コンテナに通知しないため、共有のポインタまたは共有の参照はキーとして動作するのに適しています。弱いポインタは値として使用することが安全です。
弱いポインタは
IsValid
関数を提供しますが、IsValid
を確認してもオブジェクトが一定期間有効であり続けることは保証されません。これは特にスレッド セーフな共有のポインタに当てはまります。別のスレッドの動作によっていつでも無効になる可能性があるからです。Pin
関数は格納したオブジェクトへの逆参照またはアクセスにつながる確認のために推奨される手段です。これは、Pin
が返す共有のポインタは、コードでクリアされるか、スコープ外になるまでオブジェクトを存続させるためです。