In this lesson, you will learn how to use TSharedPtr and TWeakPtr to safely manage memory for non-UObject C++ classes, preventing memory leaks and dangling pointers.
Why use Smart Pointers?
When you create custom C++ classes that do not inherit from UObject (meaning they aren't tracked by Unreal’s Garbage Collector), you are responsible for their memory. If you use raw pointers, you risk "memory leaks" (forgetting to delete an object) or "crashes" (trying to access an object that has already been deleted).
Unreal’s Smart Pointers automate this process using Reference Counting.
The TSharedPtr
A TSharedPtr acts like a guardian for your object. Every time you assign an object to a TSharedPtr, the reference count increases. When the pointer goes out of scope, the count decreases. Once the count hits zero, the object is automatically deleted from memory.
// Create a shared pointer to a custom data object
TSharedPtr<FMyData> DataPtr = MakeShared<FMyData>();
// You can copy this pointer freely; the count increases automatically
TSharedPtr<FMyData> AnotherPtr = DataPtr;
The TWeakPtr
Sometimes, you want to "look" at an object without technically "owning" it. If you use a TSharedPtr everywhere, the object will never be deleted because the reference count will never reach zero. This is a Circular Dependency or Memory Leak.
A TWeakPtr lets you reference an object without increasing the count. Before using a TWeakPtr, you must check if the object still exists by calling .Pin().
TWeakPtr<FMyData> WeakPtr = DataPtr;
// Check if the object still exists before accessing it
if (TSharedPtr<FMyData> LockedPtr = WeakPtr.Pin())
{
// It is safe to use the object here!
LockedPtr->DoSomething();
}
By using TSharedPtr for ownership and TWeakPtr for observation, you ensure your custom systems stay clean, predictable, and memory-efficient.
Key Takeaway: Use TSharedPtr to track ownership and automatically clean up memory, and use TWeakPtr to safely reference objects without preventing them from being destroyed.