[4.17] What happens if I call an Actor's Destroy() twice?

Im trying to track down an inconsistent and VERY infrequent crash, that the call stack says is an Access Violation. Near as I can figure I think it happens in relation to actors that I have called Destroy() on and are now “PendingKill”. In my last “once over” of the code I noticed there was a non-zero chance that the code might call Destroy() on an actor twice before the end of the tick. Ive remedied that sloppy code, but the infrequency of the crash means I probably won’t find out if that was the actual problem for sometime.

So in the interest of confirmation(and curiosity):

What kind of problems would arise from “double tapping” an Actor’s Destroy() function?

Would it result in an Access Violation Crash, or am I just being overly cautious?

We have the unreal source so let’s find out. AActor::Destory seems to first check AActor::IsPendingKillPending this function returns true if bActorIsBeingDestroyed is true. Then we see that AActor::Destory calls UWorld::DestroyActor which uses FMarkActorIsBeingDestroyed which sets bActorIsBeingDestroyed to true.
So in conclusion, calling Destroy on an actor multiple times doesn’t have any effects.

I think I may have solved my issue(of crashing) by using IsValidLowLevel() && IsValidLowLevelFast(). Instead of a crash I got several Warning messages in the Editor:

LogUObjectArray: Warning: Invalid object index -572662307

LogUObjectArray: Warning: Other object in slot

Occasionally, when I was crashing the callstack would throw “Assertion failed: Index >= 0” which I had initially thought was unrelated. But looking closer I noticed:

IsPendingKillPending() also calls IsPendingKill()

IsPendingKill() calls GUObjectArray.IndexToObject(InternalIndex)->IsPendingKill()

IndexToObject() calls check(Index >= 0)

Ive not been able to find anything yet, that would indicate how an Object’s index is modified during the destroy process, but IsPendingKillPending() is called frequently during the destroy process and if the process invalidates the InternalIndex in that process(purposefully or otherwise) then would double tapping the Destroy() function cause that Assertion Failed crash?

In any case Im still wary of the Access Violation, so I will keep testing.

EDIT:
Im also seeing a long list of “Deleted Actors” that are not going away, in the Editor’s World Outliner while testing in PIE, which is going to cause performance issues if I can’t get rid of them…

Just to be sure, you’re not using basic pointers to store the AActor ? Or you may end up call destroy on a deleted pointer the second time.