Call to RemoveDynamic in Destructor is killing engine

Hi all,

I’ve set up a simple Event Dispatcher using Delegates (DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam) which I have as an object on my GameState class.

Everything is going fine with the setup, AddDynamic registering of the listener and I’m hearing the event correctly. My problem is how to I Unbind this correctly? I am making a call to ‘RemoveDynamic’ within the class destructor but this is crashing the engine.

Any help greatly received on how to do this… here is my code of the listener class…

// Copyright 2016 Polypusher Studios Ltd. All Rights Reserved.

#include "MM2.h"
#include "MM2GameState.h"
#include "TestReceiveEventActor.h"


// Sets default values
ATestReceiveEventActor::ATestReceiveEventActor()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	UE_LOG(LogTemp, Warning, TEXT("HELLO from ATestReceiveEventActor"));
}

// Default Destructor
ATestReceiveEventActor::~ATestReceiveEventActor()
{
	UE_LOG(LogTemp, Warning, TEXT("HELLO from ATestReceiveEventActor DESTRUCTOR!!!"));
	
	// Unregister the listener
	MyGameState->GlobalEventHandler->TimerComplete.RemoveDynamic(this, &ATestReceiveEventActor::Test);
}

// Called when the game starts or when spawned
void ATestReceiveEventActor::BeginPlay()
{
	Super::BeginPlay();
	
	// Register the listener
	MyGameState = GetWorld()->GetGameState<AMM2GameState>();
	MyGameState->GlobalEventHandler->TimerComplete.AddDynamic(this, &ATestReceiveEventActor::Test);
}

// Called every frame
void ATestReceiveEventActor::Tick( float DeltaTime )
{
	Super::Tick( DeltaTime );

}

void ATestReceiveEventActor::Test(uint8 SomeInt)
{
	UE_LOG(LogTemp, Warning, TEXT("WE HAVE RECEIVED AN EVENT in C++!!!: %d"), SomeInt);
}

I have found the answer to this. It seems that by the time the destructor gets called the pointers for either MyGameState or GlobalEventHandler have already been lost, this is making the engine crash when clicking the stop button.

I added the code to ::EndPlay() instead, which seems to be a ‘first stage of destroying’, and everything seems™ to be working correctly.

void ATestReceiveEventActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason);
	
	// Unregister the listener
	if (MyGameState)
	{
		UE_LOG(LogTemp, Warning, TEXT("HELLO from ATestReceiveEventActor EndPlay()!!!:: %s"), *MyGameState->GetName());
		MyGameState->GlobalEventHandler->TimerComplete.RemoveDynamic(this, &ATestReceiveEventActor::Test);
	}
}

I wasn’t aware that there even is a EndPlay function prior to right now, but possibly worth noting that BeginDestroy is a good function to override for cleaning up components, also

HOWEVER, EndPlay may be better if you have to access anything else in the world, as BeginDestroy is called after invalidating the object.