Clarification on safe usage of TWeakObjectPtr

Question about TWeakObjectPtr, trying to understand a bit more about Unreal garbage collection / check if I’m not understanding something correctly.

I see a lot of examples in my project’s code like the following, contained in a member function of a UObject derived class:

	SomeObject->GetThingAsync().Then([WeakThis = MakeWeakObjectPtr(this)](const SD::TExpected<TSomeResult>& Result)
		{
			TSomeResult Profile;
			if (!WeakThis.IsValid())
			{
				return;
			}
                        WeakThis->DoSomething();
                        ...
                }

Note that this code and the continuation/callback are all being executed on our game’s main/game thread.

The question is, is this code unsafe?

Option #1 Reasoning that it is unsafe: If you just call WeakThis.IsValid(), there is no guarantee that your object/pointer will remain valid for any length of time after that check. I think implicit in this is that garbage collection could happen on another thread interleaved with your code running on the game thread. So the object could get cleaned up out from under us.

Instead with a weak pointer, you need to call Pin() to get a hard refcount to the object (by constructing a TSharedObjectPtr) and then it is safe to use (while the TSharedObjectPtr object is still alive and holding the refcount). See also this doc: https://dev.epicgames.com/documentation/en-us/unreal-engine/weak-pointers-in-unreal-engine

// Acquire a Shared Pointer from the Weak Pointer and check that it references a valid object.
if (TSharedPtr<FMyObjectType> StrongThis= WeakThis.Pin())
{
	// The Shared Pointer is valid only within this scope.
	// The object has been verified to exist, and the Shared Pointer prevents its deletion.
	StrongThis->SomeFunction();
}

Option #2 Reasoning that it is safe: We are guaranteed that any UE garbage collection step that could invalidate the object being pointed to by WeakPtr must happen on the main game thread, and so there is no problem as long as all this code is running on the main game thread.

[Attachment Removed]

Steps to Reproduce
N/A

[Attachment Removed]

Hello!

The part of the GC that can invalidate UObjects is guaranteed to run on the Game thread. As you mentioned that the callback is also going to run on the Game thread, this is Option 2 and is fully safe.

In the case where the callback can run on other threads than the Game thread, you will still want to use a weak pointer but take action to prevent the pointer from invalidating while using it. There are 2 options:

  • TWeakObjectPtr::TryPin (or Pin): As you already stated with Option 1. this tries to create a StrongObject pointer which will count as a reference to the object if the GC fires. The referenced object might leak until the next GC so the code must take this in consideration.
  • FGCScopeGuard: Guarantees that the scoped code will not run concurrently with the GC. Use this if you don’t want the object to leak and don’t mind the possibility of the GC being delayed while the guard exists.

Regards,

Martin

[Attachment Removed]