シェアードポイント は強力な Nullable 型スマートポインタです。共有のポインタは本質的に、スマートポインタの全ての基本的なメリットを持ち、メモリリーク、ダングリング ポインタ、初期化されていないメモリへのポインタをやメモリが初期化されないことなどを防ぎます。同時に以下のような機能もあります。
共有のオーナーシップ 参照カウントによって、複数の共有のポインタに対して参照されている間は参照しているデータ オブジェクトが絶対に削除されないようにできます。
自動無効化 : Volatile オブジェクトをダングリング ポインタを心配せずに安全に参照できます。
弱い参照カウント: Weak Pointers は参照サイクルを中断します。
目的表示: オブザーバーとオーナーを区別し、(共有の参照) non-nullable 型の参照を提供します。
共有のポインタには注目すべき基本的な性質があります。
非常に堅牢なシンタックス
非侵入型 (しかしリフレクションは可能)
スレッドセーフ (条件付き)
優れたパフォーマンス、メモリへの負担が軽減
共有のポインタは 共有の参照 と似ています。大きな違いは、共有の参照が Nullable 型でないため常に参照が有効なオブジェクトである点です。共有の参照と共有のポインタのどちらかを選ぶとしたら、空または Nullable 型オブジェクトが必要な場合を除いて共有の参照を選ぶとよいでしょう。
宣言と初期化
共有のポインタは Nullable 型なので、データ オブジェクトの有無に関係なく初期化できます。以下は、新しい共有のポインタを作成する例です。
// 空の共有のポインタを作成します
TSharedPtr<FMyObjectType> EmptyPointer;
// 共有のポインタを新しいオブジェクトに作成します
TSharedPtr<FMyObjectType> NewPointer(new FMyObjectType());
// 共有の参照から共有のポインタを作成します
TSharedRef<FMyObjectType> NewReference(new FMyObjectType());
TSharedPtr<FMyObjectType> PointerFromReference = NewReference;
// スレッドセーフの共有のポインタを作成します
TSharedPtr<FMyObjectType, ESPMode::ThreadSafe> NewThreadsafePointer = MakeShared<FMyObjectType, ESPMode::ThreadSafe>(MyArgs);
2 つめのサンプルでは、そのオブジェクトを参照している共有のポインタがないので、NodePtr
は効率駅に新しい FMyObjectType
オブジェクトを維持します。そのオブジェクトを指定する共有のポインタまたは共有の参照がなく、NodePtr
は範囲外になると、オブジェクトは破壊されます。
共有のポインタをコピーすると、参照するオブジェクトへの参照が 1 つ追加されます。
// ExistingSharedPointer が参照しているオブジェクトの参照カウントを増やします
TSharedPtr<FMyObjectType> AnotherPointer = ExistingSharedPointer;
参照する共有のポインタ (または共有の参照) がなくなるまで、オブジェクトは存在し続けます。
共有のポインタをリセットするには、Reset
関数を使用する、または以下のように null ポインタを割り当てます。
PointerOne.Reset();
PointerTwo = nullptr;
// PointerOne と PointerTwo は両方とも nullptr を参照するようになりました。
MoveTemp
(または MoveTempIfPossible
) 関数を使って、共有のポインタのコンテンツを別の共有のポインタへ転送することができます (移動元の共有のポインタは空になります)。
// PointerOne のコンテンツを PointerTwo に移動します。PointerOne はこの後 nullptr を参照します。
PointerTwo = MoveTemp(PointerOne);
// PointerTwo のコンテンツを PointerOne に移動します。PointerTwo はこの後 nullptr を参照します。
PointerOne = MoveTempIfPossible(PointerTwo);
MoveTemp
と MoveTempIfPossible
の違いは、MoveTemp
には 非定数型左辺値 (lvalue) 上でのみ実行できる静的アセットが含まれていることです。
共有のポインタと共有の参照間の変換
共有のポインタと共有の参照間での変換は一般的です。共有の参照は暗示的に共有のポインタへ変換し、新しい共有のポインタは有効なオブジェクトを参照するという保証が追加されています。変換は通常の記法で処理されます。
TSharedPtr<FMyObjectType> MySharedPointer = MySharedReference;
共有のポインタが non-null オブジェクトを参照している限り、Shared Pointer
関数の ToSharedRef
を使って共有のポインタから共有の参照を作成できます。null の共有のポインタから共有の参照を作成しようとするとアサートに問題が発生します。
// アサーションの可能性を避けるため、逆参照する前に共有ポインタが有効であることを確認します。
if (MySharedPointer.IsValid())
{
MySharedReference = MySharedPointer.ToSharedRef();
}
比較
共有のポインタ同士で等値をテストすることができます。ここでの等値の定義は、両方の共有のポインタが同じオブジェクトを参照していることです。
TSharedPtr<FTreeNode> NodeA, NodeB;
if (NodeA == NodeB)
{
// ...
}
IsValid
関数と bool
演算子は共有のポインタが有効なオブジェクトを参照するかどうかを設定します。Get
を呼び出して有効な (non-null) オブジェクト ポインタを返すかどうか確認することもできます。
if (Node.IsValid())
{
// ...
}
if (Node)
{
// ...
}
if (Node.Get() != nullptr)
{
// ...
}
逆参照とアクセス
ポインタの逆参照、メソッドの呼出し、そしてメンバへのアクセスは、通常の C++ ポインタと同じ方法で設定します。また、逆参照を行う前に、IsValid`関数を呼び出す、またはオーバーロードされた
bool` 演算子を使って、C++ ポインタに対して行うようにヌルチェックも実施すべきです。
// 再参照する前にノードが有効なオブジェクトを参照していることを確認します。
if (Node)
{
// 次の 3 つのコードのいずれかが、ノードを逆参照し、そのオブジェクトに対して ListChildren を呼び出します:
Node->ListChildren();
Node.Get()->ListChildren();
(*Node).ListChildren();
}
カスタム デリータ
共有のポインタと共有の参照は、参照しているオブジェクトに対するカスタム デリータをサポートしています。カスタム削除コードを実行するには、スマート ポインタの作成時にパラメータとして実行するラムダ関数を以下のように指定します。
void DestroyMyObjectType(FMyObjectType* ObjectAboutToBeDeleted)
{
// カスタム仕様の削除コードがここに入ります。
}
// これらの関数はカスタム仕様の削除でsmartポインタを作成します。
TSharedRef<FMyObjectType> NewReference(new FMyObjectType(), [](FMyObjectType* Obj){ DestroyMyObjectType(Obj); });
TSharedPtr<FMyObjectType> NewPointer(new FMyObjectType(), [](FMyObjectType* Obj){ DestroyMyObjectType(Obj); });