What is the correct way to share UObject (UPROPERTY)

I have two AActors and one UObject that is shared between them. Below is some example code (not the real code because the real code would be way too large). What is the proper way to share the UObject? In particular I am concerned about garbage collection and the ramifications of having the UPROPERTY declared in two different classes (possibly with conflicting parameters). Also, as a sort of side question, why do I have to pass the spawn location twice when using SpawnActorDeferred?



UCLASS()
class UShared : public UObject
{

...

}

UCLASS()
class AParent : public AActor
{

...

public:

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Child)
TSubclassOf<AChild> ChildTemplate;

AChild* SpawnChild(FVector Location)
{
	UShared* NewShared = NewObject<UShared>();
	SharedObjects.Add(NewShared);

	FTransform SpawnTransform;
	spawnTransform.SetLocation(Location);

	AChild* Child = GetWorld()->SpawnActorDeferred<AChild>(ChildTemplate, SpawnTransform, this);
	Child->SetSharedObject(NewShared);
	Child->FinishSpawning(SpawnTransform);

	return Child;
}

private:

UPROPERTY(Transient)
TArray<UShared*> SharedObjects;

...

}

UCLASS()
class AChild : public AActor
{

...

public:

void SetSharedObject(UShared* SharedObject)
{
	this->SharedObject = SharedObject
}

private:

UPROPERTY(Transient)
UShared* SharedObject;

...

}


When sharing objects, there is usually a logical “owner” to which the lifespan of the object is tied, in this case AParent. (You could even go as far as making AParent its Outer.) This should be the only class owning a hard pointer to the shared object. All children being shared to should use a weak pointer, as so:



UPROPERTY(Transient)
TWeakObjectPtr<UShared> SharedObject;


Unlike a hard pointer, the weak object pointer does not prevent an object from getting garbage collected. So if AParent gets destroyed somehow, AChild won’t prevent the shared object from getting collected. Weak pointers have functions IsValid() and IsStale() that respectively let you know if the pointed object is valid at all and if it was once valid but was destroyed.

If your shared object has a longer lifespan than AParent (i.e.: AChild could still use it after AParent is destroyed), then a hard pointer is fine, though the way you’ve written your example doesn’t seem to express this goal.

-Camille

Thank you Camille for the very clear explanation.

You are correct that I do not intend for AChild to outlive AParent (this sentence all of a sudden seems really depressing).

It’s not uncommon for children to become “detached” in such a way, the easy fix is to store a reference to them in your game class, for example. As long as someone references the actor through a UPROPERTY() pointer, it won’t get deleted.