How to destroy actor in C++?

I have a ALevelSequenceActor* SequenceActor that was created when I called the ULevelSequencePlayer::CreateLevelSequencePlayer function in a subsystem method I wrote. When my sequence finished playing the SequenceActor was still visible in the World Outliner in the unreal editor. Replaying the sequence created another SequenceActor so the World Outliner was being flooded with ALevelSequenceActor. I decided to figure out how to safely delete objects in the world through the code, and I found this thread from 2014 that had a custom written function in it that would allow the deletion of UObjects because no other way existed in the engine.

Well it’s been 8 years since that post. Has the engine had functionality added to it since then to delete objects and actors, or is this thread still the best way to do that? Ideally I’m looking for a single function call to delete an actor and remove it from the World Outliner.

Here is my code for reference:

.h header file
//The array of LevelSequences to be played.
TArray<ULevelSequence*> CameraRoute;
//These pointers play the level sequences in CameraRoute.
ULevelSequencePlayer* SequencePlayer;
ALevelSequenceActor* SequenceActor; //<- I have to delete this actor manually or he floods the editor when I play many ULevelSequences.
//Called when a sequence is finished to start the next sequence.
FScriptDelegate SequenceFinishedDelegate;
.cpp file
bool RunRoute()
{
   if (CameraRoute.Num())
   {
      UWorld* CurrentWorld = GetWorld();

      if (CurrentWorld != nullptr)
      {
         FMovieSceneSequencePlaybackSettings PlaybackSettings;

         SequencePlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(CurrentWorld->PersistentLevel, CameraRoute[iCurrentSequence], PlaybackSettings, SequenceActor);

         if (SequencePlayer != nullptr)
         {
            SequencePlayer->OnFinished.Add(SequenceFinishedDelegate);
            SequencePlayer->Play();
            return true;
         }
      }
   }
   return false;
}

void OnSequenceFinished()
{
   iCurrentSequence++;
   if (iCurrentSequence < CameraRoute.Num())
   {
      //There are more sequences to play, destroy the SequenceActor from the previous sequence before starting a new one. Otherwise the SequenceActor will remain in the World Outliner.
      VDestroy(SequenceActor);
      RunRoute();
   }
   else
   {
      //Sequences finished playing.
      iCurrentSequence = 0;
      //Destroy the last SequenceActor.
      VDestroy(SequenceActor);
   }
}

void VDestroy(UObject* ToDestroy)
{
   if (!ToDestroy) return;
   if (!ToDestroy->IsValidLowLevel()) return;
   //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   
   //Actor?
   AActor * AnActor = Cast(ToDestroy);
   if (AnActor)
   {
      AnActor->K2_DestroyActor();
      ToDestroy = NULL;
   }
   
   //Object - BeginDestroy
   else
   {
      //Begin Destroy
      ToDestroy->ConditionalBeginDestroy();
      ToDestroy = NULL;
   }
   
   //GC
   GetWorld()->ForceGarbageCollection(true);
}

So I’ve searched more on this topic and found 3 ways to destroy an actor.

	//Will destroy an AActor, but I think this pointer HAS to be an AActor. So if you accidentally cast something to an AActor that isn't an actor this may not work.
	Actor->Destroy();

	//Calls ->Destroy()
	Actor->K2_DestroyActor();
	
	//Destroys a UObjectBaseUtility, which is parent to UObject, so I think this one is safe to call on pretty much everything. However, this will leave a (Deleted Object) in the World Outliner. You can clear those out by pressing F5 in the window. Not sure if there is a way to keep that window cleared in code.
	Actor->MarkPendingKill();

After calling these functions it’s also recommended to call

GetWorld()->ForceGarbageCollection(true)

though I’m not entirely sure when it’s necessary and when it’s not.

Then there is the function that Rama wrote in 2014 that takes a UObject, and checks if it’s an AActor to clean it up.

void VDestroy(UObject* ToDestroy)
{
   if (!ToDestroy) return;
   if (!ToDestroy->IsValidLowLevel()) return;
   //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   
   //Actor?
   AActor * AnActor = Cast(ToDestroy);
   if (AnActor)
   {
      AnActor->K2_DestroyActor();
      ToDestroy = NULL;
   }
   
   //Object - BeginDestroy
   else
   {
      //Begin Destroy
      ToDestroy->ConditionalBeginDestroy();
      ToDestroy = NULL;
   }
   
   //GC
   GetWorld()->ForceGarbageCollection(true);
}

Hey, I’ve been recently researching into this.

Been experimenting with ConditionalBeginDestroy() since it is asynchronous.

It also allows me to override these two to track current state of the kill:

void AAnyActor::BeginDestroy()
{
	UE_LOG(LogTemp, Error, TEXT("%s->BeginDestroy()"), *this->GetActorNameOrLabel()); // Returns name.

	Super::BeginDestroy();

	UE_LOG(LogTemp, Error, TEXT("%s->BeginDestroy()"), *this->GetActorNameOrLabel()); // None
}
void AAnyActor::FinishDestroy()
{
	UE_LOG(LogTemp, Error, TEXT("%s->FinishDestroy()"), *this->GetActorNameOrLabel()); // None

	Super::FinishDestroy();

	UE_LOG(LogTemp, Error, TEXT("%s->FinishDestroy()"), *this->GetActorNameOrLabel()); // None
}

I’ve noticed FinishDestroy() does not executed immediatly and most of the time it seems to accumulate with other actors pending to be collected.

GEngine->ForceGarbageCollection(true); … if I’m not mistaken, this eventually calls this other function:

void UEngine::PerformGarbageCollectionAndCleanupActors()
{
	// We don't collect garbage while there are outstanding async load requests as we would need
	// to block on loading the remaining data.
...
}