How to prevent garbage collecting the UObject which created in function?

I created a camera shake tool that can shake the camera at intervals and stop automatically after specific duration time.

Just like below code, I created a UCameraShaker instance which derived from UObject, assigned to a TWeakObjectPtr, and saved the ptr to a TArray(maybe this step was unnecessary) which was a member variable with UPROPERTY().

I knew that TWeakObjectPtr cannot prevent the GC operation, so seconds later, the instance of UCameraShaker I just created would be destroyed, unsurprisingly.

I have no idea that how to keep these instances and will not be destroyed by GC. Add to root? But I think I can’t decide when to remove from root because there is no callback when the timer expired. Add reference count? How?

UCLASS(MinimalAPI)
class UCameraShakeHelper : public UKMObject
{
	GENERATED_UCLASS_BODY()

public:
	~UCameraShakeHelper();

	UFUNCTION(BlueprintCallable, Category = "UCameraShakeHelper")
	void ShakeCameraWithInterval(TSubclassOf<class UCameraShake> Shake, float Scale, float Interval, float TotalTime);

private:
	UPROPERTY()
	TArray<TWeakObjectPtr<UCameraShaker> > CameraShakerList;
};

void UCameraShakeHelper::ShakeCameraWithInterval(TSubclassOf<class UCameraShake> Shake, float Scale, float Interval, float TotalTime)
{
	UWorld *World = GetWorld();
	if (nullptr != World)
	{
		auto GameInstance = Cast<UROG2GameInstance>(World->GetGameInstance());
		TWeakObjectPtr<UCameraShaker> Shaker = NewObject<UCameraShaker>(this);
		Shaker->InitParams(Shake, Scale);
		CameraShakerList.Add(Shaker);
		auto &TimerHelper = GameInstance->GetTimerHelper();
		TimerHelper.SetAutoStopTimer(Shaker.Get(), &UCameraShaker::OnShake, Interval, TotalTime);
	}
}

You can declare the array as follows (using regular pointers):

Header:

UPROPERTY()
TArray<UCameraShaker*> Shakers;

Cpp:

UCameraShaker* shaker = NewObject<UCameraShaker>(this, UCameraShaker::StaticClass());
Shakers.Add(shaker);
1 Like

It works, but what if the Shakers array was removed? If I add the shaker to the array, I have to add a callback function to remove it from the array when the timer expire. So I want to make a optimization and remove this array. How to keep the shaker alive without Shakers array?

Good idea! I’ll have a try~
Thank you~

Is there anything else method to keep a object alive? Such as add reference count manually or something else?

You can just declare a class-level variable decorated with UPROPERTY(), e.g.

UPROPERTY()
UCameraShaker* Shaker;

This will instruct the GC to keep it alive until all references to it has been removed.

Crap, I was editing the previous comment and deleted it. Here it is:

=========================

Yes, I don’t think there’s really a perfect solution here. You could remove the array and have a single shaker reference decorated with UPROPERTY() to prevent Garbage Collection, but you’d still have the same problem. The point is that even with built-in GC, you still need to instruct it what to do in many cases.

You could add a callback to call Destroy on the shaker after it’s been used (whether it’s in an array or not) as you’ve suggested, but this means you’d have to spawn a new one each time you do a shake. Compared to keeping the reference alive (see below) this might actually be worse performance-wise.

On the other hand you can just keep this reference alive and re-use (re-init) it each time you need to do a shake. I do this in my project, and the performance hit seems negligible.

=========================

Not that I know of.

Is there anything else method to keep a object alive? Such as add reference count manually or something else?