Actors are always explicitly destroyed. You can not keep an actor alive by holding a pointer to it (the world marks it as pending kill which flags to the GC to clear it up). Other UObjects on the other hand, need a UPROPERTY to keep it alive, as the GC will check to see if any UPROPERTY is holding a pointer to that object, if not, it cleans it up.
So a TWeakObjectPtr for an AActor is not really needed. For normal UObjects, it makes sense, if the class that is holding a pointer to it should not keep it alive.
There IS come caveats with ActorComponents though. The DestroyActor function will actually mark all components the Actor has as PendingKill. BUT components can be GC’d if they are not held by a strong pointer that is UPROPERTY as AActor does NOT hold components in a UPROPERTY container.
So in a nutshell, TWeakObjectPtr makes sense if you don’t want to keep an Object alive but want to hold a pointer to it. This mainly is related to UObject, and not so much with Actor/ActorComponent (with some caveats explained below). BUT in order for an object to stay alive it must be in the root set OR have a raw pointer with UPROPERTY. Actors are handled by the world, and the world keeps them alive.
One of the other uses for a TWeakObjectPtr over a UPROPERTY is you don’t need to be in a full reflected scenario. Say for instance you have a normal non reflected struct. You can hold a TWeakObjectPtr to an Actor, but you can not hold a UPROPERTY to that Actor. One of the caveats with the GC system is it needs a full line of reflection.
TWeakObjectPtr<AActor> WeakActor;
This does not need to be UPROPERTY for the GC to invalidate the pointer. Another example is this:
USTRUCT()
struct FMyStruct
{
GENERATED_BODY()
TWeakObjectPtr<AActor> WeakActor; //This will be marked stale/invalid when actor is gone.
UPROPERTY()
AActor* NonWeakActor; //This will not be nulled when the actor is destroyed, and will point to invalid memory (dangling pointer)
};
UCLASS()
class MYGAME_API UMyObject : public UObject
{
GENERATED_BODY()
FMyStruct MyStruct;
};
In the above you can not use UPROPERTY on your pointer, so you need to hold TWeakObjectPtr here inside your struct. Even though your struct is a USTRUCT you broke the reflection chain by not using UPROPERTY on the FMyStruct. You could hold a raw pointer here with UPROPERTY() but this will NOT be nulled out and will be dangling if the Actor goes away.
I can give more examples, but hopefully this helps?