How long is a TSoftObjectPtr valid?

According to docs if you do an async load on a reference from TSoftObjectPtr the resulting reference is guaranteed only upto the point the delegate is executed.

However this means that you need to store that soft/weak reference to a hard reference if you want it to persist past the delegate call or cache it for later use.

The obvious downside is that you now have to maintain two variables one the TSoftObjectPtr reference that was used to assign that asset reference and then another hard reference (UPROPERTY or Shared ptr) to actually keep it safe after its loaded. This might not be ideal and causes problems with naming conventions of variables

Is there a way to keep the TSoftObjectPtr loaded persistently and avoid using a second variable as hard reference ?

I’ve always felt the TSoftObjectPtr isn’t meant to be the normal reference to the object, more a helper. You have to ground it somewhere to avoid GC. There are some hack’y ways around this but you’re better off storing a hard reference to the object.

That is true, but it also means that you gotta maintain two vars for each object , one for soft reference and one for hard. I looked into encapsulating the template with a shared ptr but the way engine handles TSoftObjectPtr as UPROPERTY internally it makes the change even more unfeasible than having two vars.

This should be a requested feature where a container should exist than can be used as UPROPERTY template in editor as well as be convertible to hard reference when needed. Until then we gotta keep hidden hard refs

That’s pretty much the point of it IIRC?

When you load something, you need to keep a hard reference to it somewhere or the engine will unload it. The SoftPtr exists so that you don’t keep the item loaded when it’s not in use, same way weak pointers are cleared when they are the only reference to something.

Exactly, the TSoftObjectPtr is just a clean helper for loading content. You still need to keep the hard reference to the object being loaded. If you really want to avoid having the hard reference, you could try the FGCObject approach and use AddReferencedObjects() to keep the soft reference alive. That ugly and it really defeats the purpose of soft references but it should work.

Well yeah , but I’m talking about something that uses SoftPtr as a part of it and handles storing that hard reference internally automatically such that you can have the advantages of both the async loading and direct assignment in editor without having to manually assign a hard reference for each asset you need.

Especially because you cannot create templatized UPROPERTY yourself without doing some major additions in various parts of core of the engine and more often than not you’d want the async loaded content to stay around so that case is not adequetly covered with async loading containers.

You don’t need a templated UProperty, you can just store it as a UObject* (which all TSoftObjectPtrs must be) and that should be it.

TSoftObjectPtr MyAsset;

UObject* MyLoadedAsset; // Set the loaded asset returned by MyAsset to this.

I think he’s looking for a way to avoid the double declaration + Bookkeeping.


.GetAsset() will load the object and return a pointer to it.
.ToSoftObjectPath() can be used to create a SoftObjectPtr().

Yes! it feels like boilerplate when you have declare variable for hard reference again and then assign to it in the delegate call, especially in cases where you want the object to persist after load and only looking for async load for saving load time hitches instead of unloading it before time.

Maybe the use case engine developers had in mind was to load something aync , use it within the delegate and then leave it to the GC to dispose of it.

I could bundle all dynamically loadable objects in a container uclass and then use a soft reference to that container which will reduce double declaration to only 1 var but with many classes would bloat the code fast.