TArrays of UObjects or UStructs that have UObjects in it will be safe, but you are responsible for the general memory cleanup of any TArray footprint that isn’t a UObject.
The idea is that UPROPERTY() adds the appropriate information about reachability/discoverability for objects so that the garbage collector can determine if an object is alive. A TArray MyThing; would leak memory if you didn’t free it yourself, with or without the UPROPERTY(). Arguably this wouldn’t even need to be a UPROPERTY().
UPROPERTY() also gives you visibility to the variables at runtime from the console window (assuming the var can be described as viewable types).
For example, you can do
~
displayall PlayerController PlayerState
and you will see all the player state objects in the game dynamically, because PlayerState is a UPROPERTY on PlayerController
similarly you can do
~
displayall PlayerState PlayerName
because PlayerName is an FString marked as a UPROPERTY and the engine knows how to display an FString