Your might have heard that Unreal's smart pointers (
TUniquePtr) should not be used on
UObjects, because the
UObject memory management system is geared for game code, which is much more garbage collection oriented.
A clear distinction between what is exposed to the uobject memory management system and what not should not be foreign. That's the reason this article exists.
Drawing the line
|Not compatible with UObject||Compatible with UObject|
TWeakObjectPtr doesn't prevent Garbage Collection and always returns
NULL when the underlying object is destroyed (regardless of being marked with
UPROPERY(), in case you wonder).
A great example of where
TWeakObjectPtr shines is its usage by the series of
DECLARE_DYNAMIC_ delegate variants. (It actually uses the non-generic
FWeakObjectPtr, which implies
The macros that declare a dynamic delegate create a class that inherits from
TBaseDynamicDelegate, which inherits from
TScriptDelegate stores the object bound to the delegate as
FWeakObjectPtr, which makes a lot of sense if you think about how you would logically expect the ownership to be handled:
The binding should not prevent the object from being destroyed!
Ways the engine uses TWeakPtr or TSharedPtr
The primary way
UGameplayTagManager stores and retrieves Gameplay Tags is by storing them as nodes in a tree-like fashion, parallel to how Gameplay Tag strings maintain their hierarchy with dot delimiters.
Those nodes are stored as
TSharedPtr<FGameplayTagNode>, which reminds me of how
std::shared_ptr is commonly used for creating tree-like relationships.
After all, lots of engine modules make use of
TWeakPtr for managing non-uobject classes, but those classes cannot participate in unreal separate memory tracking system geared for game code.
Let's not forget mentioning
TSharedFromThis, which is the class many classes derive from to directly get an instance as
It's used extensively by many things which are rarely related to the entire surface-level Player Controller, Player State, Pawn, etc. paradigm.
TSharedPtris excellent for managing the lifetime of tree-like nodes. These nodes can't simultaneously participate in Unreal's separate memory tracking system geared for game-code, thus should not be
Garbage collection reliance allows an easy scripting experience, as the allocated memory gets handled automatically and intelligently.
Raw pointers that aren't marked with
UPROPERTY()are not exposed to the reflection system, and thus won't explicitly be set to
nullptrwhen the address should no longer be accessed.
IsValid()could crash the game; it might be a dangling pointer because it wasn't explicitly set to
Suppose you're storing the address of garbage collectable class instances through a pointer. In that case, it's great to mark that field with
UPROPERTY(), so the reflection system can null it for you, making
nullptra reliable way to test the validity of an object.
IsValid()is a more streamlined approach for game code, as it combines some flag tests such as