Garbage collection doesn't null my pointer

Are you checking right after destroying or when the GC has actually kicked in?

308829-gc.png

Not experienced in C++ but as far as I know the actor is just marked pending kill until GC kicks in. So maybe you should check if it’s penging kill?

I expected my Actor pointer to be nulled when I destroy the Actor but I am not seeing it be nulled. What am I doing wrong?

UPROPERTY()
ATestActor* TestActor;

// Spawned in the BeginPlay of another Actor
TestActor = static_cast<ATestActor*>(GetWorld()->SpawnActor(ATestActor::StaticClass()));

// Destroyed via button press call back
TestActor->Destroy();

// How I am checking
// EDIT: this check is on a different button press
if(TestActor == nullptr)

Documentation Programming with C++ in Unreal Engine | Unreal Engine 5.3 Documentation

When an AActor or UActorComponent is destroyed or otherwise removed from play, all references to it that are visible to the reflection system (UProperty pointers and pointers stored in Unreal Engine container classes such as TArray) are automatically nulled.

Try making TestActor = Null;

After destruction.

Also there is a thread about destroying actors that I find here. [Question] How to destroy an actor properly in C++? - Programming & Scripting - Unreal Engine Forums

I guess in this case it’ll help but if I have a different Actor that had a reference to this destroyed actor it would come back to the same issue.

My setting does look like that. I’ll double check if making that shorter helps but I do see the actor disappearing from the world hierarchy immediately after running destroy.

I guess I can run some tests to see if that is a more reliable way of checking destruction than the null check. I would very much like to hear from someone at UE4 if the documentation is just outdated and you don’t check for null ptr anymore.

When an actor Destroy is called, the actor is removed from the world’s actor array, removes it from the networking list, sends EndPlay, destroys components, etc. The final thing it does is to mark the actor Pending kill. This sets an object flag called Pending Kill. At this point the Actor is still valid, but should not be used as its marked for Garbage collection.

Checking for a nullptr only is ok in most situations. But i do prefer to use the IsValid global function. This checks nullptr and pending kill. Instead of just nullptr.

SomeActor->Destroy();
if (SomeActor)
{
   SomeActor()->DoSomething(); //Would run fine, but can you trust it?
}

with IsValid():

SomeActor->Destroy();
if (IsValid(SomeActor))
{
   SomeActor()->DoSomething(); //Would never reach this, cause it is pending destroy.
}

GC only runs on a frequency, not every tick. So unless you know you won’t access that actor during the time between Destroy and Garbage collection, usig normal nullptr is ok, otherwise IsValid is just wise and preferred in mostly all cases.

The same rules can apply to UObjects, tho UObjects are normally set to be destroyed by removing all UPROPERTY references to them (setting them to nullptr), tho MarkPendingKill can be called on an UObject.

Side note: Don’t use static_cast on UObject’s. This is wrong

TestActor = static_cast<ATestActor*>(GetWorld()->SpawnActor(ATestActor::StaticClass()));

use this

TestActor = Cast<ATestActor>(GetWorld()->SpawnActor(ATestActor::StaticClass()));
1 Like