Hey there, I’ve been using Unreal Engine 4 for a little over half a year and one thing I frequently run into is the need for a class that is compatible with TSharedPtr to retain a object reference that is not weak.
My assumption has been that just having a UObject* as a member of a class (non-USTRUCT) will not keep that object from being garbage collected when nothing else references it. I have been working around this, painfully with a weak reference to the object the TSharedPtr (or ref) is created from then stowing the object references on that UObject, which is probably hindering performance with the amount of indirection.
Basically I would like to know if there is a way to have a TSharedPtr compatible type hold a object reference in the same way UObject types with UPROPERTY() do. As in if my UObject has a TSharedPtr that references other objects, treat those references as belonging to the UObject holding a smart potiner to the TSharedPtr?
(Ideally a way that doesn’t involve making virtual methods or virtual interface implementation outside of uobjects?)
You can add an implementation of AddReferencedObjects to the outer class (it’s a bit weird how it works, you actually add it as a static method; you can find examples in the engine code), and from there dig into the shared pointer to grab the object reference to pass to the collector.
Alternatively, if you are the one creating the non-reflected class (the one the shared pointer holds), you can make that class inherit from FGCObject, which has a virtual AddReferencedObjects method you can override to register the reference.
With the AddReferencedObjects approach, does it matter what ESPMode is being used no the TShared*? I am doing significant amounts of work on non-game threads so I’m already using ESPMode::ThreadSafe, since the ptr can change from the other thread but… well I guess what i’m asking is does AddReferencedObjects get invoked from an outside thread?
I’ll check out FGCObject too, but am trying to avoid any virtual tables, perhaps I can use it to make a manager of sorts though, which makes me wonder if there is a TSharedWeakPtr? otherwise would need to get into thread locking mechanisms.
The GC runs on the game thread I’m fairly sure, or at the very least it’s synced to it.
The type of shared pointer is irrelevant as far as the GC is concerned, because it has no interest in the non-reflected struct itself. You’re giving the GC (via one of the above approaches) a direct reference to a pointer to a UObject. Since the GC may want to null out that pointer if the object gets forcefully deleted (which is allowed even when there are strong references - in particular will happen with actors), you need to guarantee that the pointer itself (and therefore the struct that it’s on) can’t get destroyed asynchronously.
I don’t know exactly what it is that you’re doing, but bear in mind that UObject’s are inherently not threadsafe. You might get away with things under certain conditions, but in general they should be accessed on the game-thread only.
Thanks again for the follow up. To clarify on stuff, I’m writing a audio replayer for music, so much of it needs to be threaded. However with objects as you suggested I’m not doing anything specific with threading, but I want my native classes to be exposed as uobjects for blueprint purposes, which turns out to be a mess when I have to piggy back off other uobject’s properties for proper reflection based GC. So basically I want the uobject front end of the native types to not be collected if their only references are by non-reflection based types and benefit from not needing to weak reference them.
My solution right now is: #include "Runtime/Core/Public/Containers/Queue.h"#include "Runtime/Core/Publ - Pastebin.com (this is not the exact code, but just a generalized version of it). It works but am running into a deleter problem on things that I NewObject with the GetTransientPackage as outer. I don’t honestly know if its related but its very strange as I have one native struct that deconstructor has invalid pointer values on the crash (0xdddddddddddddddd).
The ‘CDO’ is never collected by GC and you can have static UFunctions on your UObject’s Class Default Object which can be accessed at runtime without having to hold a ‘perpetual’ pointer to it somewhere.
‘GetMutableDefault’ method give direct access to the generated object with its non-static UProperties even though you may not have instances created:
Very interesting. I feel like I don’t have a grip on UClass and assets. Is there a guide that explains what files are UClass definitions and what files are assets?
ike for example: I use a UFactory to import the music module, which is a UObject type. They basically show up like materials and sounds. I store the front end wrapper object on this module object / file that describes what instruments, patterns and notes etc exist in the native representation. Alternatively, when a music file is streamed in and not stored as a file, I generate the front end. Either way, the front end cannot go away while any number of native implementations of the data exist. If the native implementation gets deleted (TSharedPtr) from the tracker/player object or any other native references then I just release the manual reference counter.
However, if each output file from the UFactory is actually implementing something thats referable by a CDO for each song then I could get past the first part of the issue. It would be a bit scary to think the CDO never collects though if that were the case, since there are hundreds of songs in the project.