Download

Passing Ownership of a UObject disguised in a UInterface pointer

  • There is a manager which allows specification of a TSubclassOf that utilizes custom interfaces
  • Manager is only aware of interface classes
  • One interface(occurrenceinterface) creates a NewObject<T>(this, subclass) of another interface(datainterface) by using the TSubclassOf specified within manager.

I want to be able to create a copy of that object (created and referred to by interface class) within the manager for storage. The Occurrence object is deleted after the Data object is returned (by ref or pointer depending).
But because Interface classes don’t have constructors I can’t store a copy correct? And if I simply store a pointer, it will be nulled when Occurrence object(which is where the Data object) is deleted right?

The only thought I could have is to pass in a reference of the manager for NewObject<>(managerRef) as the outer for the data object.

[SPOILER]



**OccurrenceInterface.h**

static void NewOccurrence(UPurposeManager& inManager, UContext& inContext);

*//User implementation of creating Data object, passed around system as a IDataInterface*
virtual IDataInterface& CreateDataObject(UContext& inContext) = 0;

**OccurrenceInterface.cpp**

static void IOccurrenceInterface::NewOccurrence(UPurposeManager& inManager, UContext& inContext)
{ if (inManager.occurrenceInterface)
{
  [INDENT=2]UObject* obj = NewObject<UObject>(&inManager, inManager.occurrenceInterface);[/INDENT]
  [INDENT=2]if (IOccurrenceInterface* occurrence = Cast<IOccurrenceInterface>(obj))
{[/INDENT]
  [INDENT=3]inManager.CheckOccurrenceForEvent *//Here the data object created and passed in by reference should be saved*
([/INDENT]
  [INDENT=4]occurrence->CreateDataObject(inContext)[/INDENT]
  [INDENT=3]);[/INDENT]
  [INDENT=2]}[/INDENT]
  }
 


 }


[/SPOILER]

You could add a Clone() function to the interface in question.

Why must the simplest solutions always be the ones we completely overlook. In my defense, I am an amateur. Thanks!
Just to clarify though, if I create a uobject in UOccurence(that will be deleted) but make the outer of the uobject UManager, would UManager be the owner, regardless of scope? And would passing the object back to UManager through pointer/reference be safe?

It sounds like you don’t actually want a copy, you just want the object to stay alive. In which case, just passing a different object as the Outer is definitely what you should do. C++ has no concept of scope in that respect, at runtime it’s irrelevant which class or method you created the object in. If the UObject you’re creating should outlive the current this object, then don’t use it as the Outer, use something you know will have a sufficient lifetime.
Then you just need to remember to store the reference in a way that UE4 GC will know about it - eg. add it to a UPROPERTY TArray on your manager.

I’d just add that creating a UObject purely for the purpose of calling a virtual method on it before immediately letting it get deleted seems a little strange. Can’t say for sure but it suggests there’s probably a better way of structuring things if you’re finding you need to do this.

I was hoping that was the case, I’m getting a grasp on memory management, just with UE4 and their GC I wasn’t sure precisely how UObject references were handled at runtime (other than not needing to manually allocate/delete the memory). I knew about UPROPERTY storage, but I hadn’t connected assigning runtime objects to generic UPROPERTY member variables in order to maintain a reference for GC.

It did feel off, still trying to understand/apply good OOP design principles. I want this plugin to be as simple and streamlined for the user, with as few calls to the system on their end as possible (ideally just the one).

I guess I created a separate interface class from purpose manager because while I was designing it on paper, an Occurrence was a separate idea from the Purpose Manager.

The only functionality of an UOccurrence object is to convert a provided context object’s data into a legible format of a data object. I’m somewhat reluctant to move the logic into the manager as that would force them to create a custom Purpose Manager class, and it would somewhat muddle the notion of an occurrence.
This is my current logic flow(wasn’t sure how to embed a Google Drawing as an image, sorry)

I’ll have to think of a more efficient way to force the user to provide the functionality while maintaining clear purpose and ease of access to creating an occurrence. I’d even prefer to not require a reference to the manager to create an occurrence, I just couldn’t think of a way to pass the data object back to the PurposeManager without forcing the user to make a separate call to the correct manager in their logic.

Thanks for pointing it out, experienced eyes have been a huge help in learning.