Ownership of UObject pointers without a parent UObject

What is the best way to maintain garbage-collected pointers to UObjects within classes which are themselves not UObjects? From what I’ve read, Unreal provides the following facilities:

  • TSharedPtr/TUniquePtr: These are not for use with UObjects, so do not apply.
  • TWeakObjectPtr: This is a weak pointer, so will not prevent garbage collection.
  • UPROPERTY() member decorators: As far as I know, these are only allowed to be used on members of UObjects, so again do not apply when the owning object is not a UObject.
  • AddToRoot()/RemoveFromRoot(): This technically stops the UObject from being garbage-collected, but is only a suitable solution if the UObject you’re managing is completely internal. If it’s exposed to users of a library or plugin, for example, there’s nothing stopping the user calling RemoveFromRoot() on the UObject, thereby causing it to potentially be garbage-collected from under your feet.

The only reliable way I’ve found to manage this situation is to have my non-UObject class A keep a pointer to an intermediate “wrapper” UObject B, which in turn keeps a UPROPERTY-marked pointer to the target UObject C. A calls AddToRoot() on B, and B is never exposed directly outside the class, so A has full control over its lifetime. B’s pointer to C can then be passed around safe in the knowledge that it won’t be garbage collected until at least after B has been destroyed.

Is there anything that Unreal provides that would be a less clunky solution for this kind of ownership?