C++ crash while calling interface method

Hi everyone,

I am fighting for the last couple of days with a seamingly simple thing. I really hope I am missing something obvious and that this is not an engine bug.

Here is the setup:

To keep my code clean (due to various wildly different states my actor gets in) I need to handle reactions and behavior differently for each state. I’ve created the following scheme - I have an interface class:

class IActorStates
{
	GENERATED_IINTERFACE_BODY()

	ATheForestCharacter* _forestCharacter;

public:
	virtual void InitState(ATheForestCharacter* forestCharacter);
	virtual void LeaveState();

	virtual void ActivateState();

	virtual void ExecuteUpdate();
	virtual void Tick(float DeltaSeconds);
	virtual void AddControllerPitchInput(float Val);
	virtual void AddControllerYawInput(float Val);
	virtual void MoveForward(float Value);
	virtual void MoveRight(float Value);
	virtual void TurnAtRate(float Rate);
	virtual void LookUpAtRate(float Rate);
	virtual void ActionButton();
};

For each state I’ve created a separate inherited class which handles the methods like for example this one and in associated .cpp I have handlers doing the real reactions:

UCLASS()
class UActorStateIndoorWalk : public UObject, public IActorStates
{
	GENERATED_BODY()

public:

	void InitState(ATheForestCharacter* forestCharacter) override;

	void MoveForward(float Value) override;
	void MoveRight(float Value) override;

	void AddControllerPitchInput(float Val) override;
	void AddControllerYawInput(float Val) override;

	void ActionButton() override;

	void Tick(float DeltaSeconds) override;

};

In header file of my character I have this:

	IActorStates* _availableActorStates[10];

	IActorStates* _currentActorState;

At the beginning I initialize it like this (I did have originally NewObject, but I thought he is a culprit, but as it turned out, he wasn’t):

	_availableActorStates[0] = ConstructObject<UActorStateIndoorWalk>(UActorStateIndoorWalk::StaticClass());
	_availableActorStates[1] = ConstructObject<UActorStateNonInteractive>(UActorStateNonInteractive::StaticClass());
	_availableActorStates[2] = ConstructObject<UActorStateEyeTurner>(UActorStateEyeTurner::StaticClass());


	for (int a = 0; a < 3; a++)
	{
		_availableActorStates[a]->InitState(this);
	}

Eventually what my own SwitchState does is that it simply changes _currentActorState to the correct pointer.

Now this is where the fun starts! It works like charm!!! For a minute or three and the it crashes :slight_smile:

This is the method where it crashes:

void ATheForestCharacter::MoveForward(float Value)
{
	IActorStates*  tmp = _currentActorState;

	if (tmp)
	{
		tmp->MoveForward(Value); // crashes on this line
	}
}

Note that I used tmp again as a result of endless debugging. Original code was:

if (_currentActorState)
{
	_currentActorState->MoveForward(Value); // crashes on this line 
}

This is what happens, but not right away - it’s actually after some time which makes it hard to hunt down.

Exception Code: 0xC0000005
Exception Information: The thread tried to read from or write to a virtual address for which it does not have the access

There are no other actions everything else is switched off so it’s basically just the walk and also no state switching takes place.

My only concern is that the event is bound like this:

InputComponent->BindAxis("MoveForward", this, &ATheForestCharacter::MoveForward);

Can it be that’s it’s a stack corruption caused by rapid executing of the method?

I would be really sad if I had to abandon my idea that input gets treated by actor’s state object as it would elegantly eliminate all nasty if constructions.

Thank you so much for any help!

Jan

EDIT: For clarity adding IActorStates cpp file:

#include "TheForest.h"
#include "IActorStates.h"

UActorStates::UActorStates(const class FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{

}

void IActorStates::ExecuteUpdate() {}
void IActorStates::Tick(float DeltaSeconds) {}
void IActorStates::AddControllerPitchInput(float Val) {}
void IActorStates::AddControllerYawInput(float Val) {}
void IActorStates::MoveForward(float Value) {}
void IActorStates::MoveRight(float Value) {}
void IActorStates::TurnAtRate(float Rate) {}
void IActorStates::LookUpAtRate(float Rate) {}
void IActorStates::Jump() {}
void IActorStates::StopJumping() {}

void IActorStates::ActionButton() {}
void IActorStates::RunKeyPressed() {}
void IActorStates::RunKeyReleased() {}

void IActorStates::FlashlightKeyPressed() {}
void IActorStates::MobileKeyPressed() {}

void IActorStates::InventoryKeyPressed() {}
void IActorStates::MenuKeyPressed() {}

void IActorStates::InitState(ATheForestCharacter* forestCharacter) { _forestCharacter = forestCharacter; }
void IActorStates::LeaveState() {}

Are you providing default implementations for all your IActorStates interface? You need to.

Only to those events which are overriden. Thank you, I will try to implement all methods.

When I say implement, I mean IActorStates::*, not implementing them in the classes which actually implement IActorStates.

Yes, thanks again. That’s what I meant. I implemented only those methods, which I needed to override. I’ve just now added empty bodies for all of them and I will see if this helps the situation.

Unfortunately this didn’t work. Still crashes at the same place. Takes 1 or 2 minutes of walking and the crash is there.

I noticed that nowhere in your code do you show where _currentActorState is set. And you should be using NewObject, not ConstructObject.

I also notice that you aren’t using UPROPERTY’s to define your uobject class members. It may be causing them to get garbage collected.

You should change your header to:

	UPROPERTY()
	TArray<IActorStates*> _availableActorStates;

	UPROPERTY()
	IActorStates* _currentActorState;

And add a line prior to your initialisation of the array,

_availableActorStates.SetNum( 10 );

Still nothing :frowning:

I can’t make TArray _availableActorStates; and UProperty but I used the array and populated it like this:

_availableActorStates.Add(NewObject<UActorStateIndoorWalk>());
_availableActorStates.Add(NewObject<UActorStateIndoorWalk>());
_availableActorStates.Add(NewObject<UActorStateNonInteractive>());
_availableActorStates.Add(NewObject<UActorStateEyeTurner>());


for (int a = 0; a < 4; a++)
{
	_availableActorStates[a]->InitState(this);
}

_currentActorState = _availableActorStates[0];

UPROPERTY() requires me to use some TScriptInterface. I will try experimenting with that too, but the crash is always the same line. Somehow the object gets wiped.

UPROPERTY is what stops it being deleted. Find a way to add it or don’t use UObjects.

Thank you! After some tweaking it’s working now. I would have never found this myself!

So the proper way to do it is:

  1. Create this definition:

    UPROPERTY()
    TArray<TScriptInterface<IActorStates>> _availableActorStates;
    
    UPROPERTY()
    TScriptInterface<IActorStates> _currentActorState;
    
  2. Initialize it in BeginPlay() otherwise it gets dumped:

    _availableActorStates.Add(TScriptInterface<IActorStates>(NewObject<UActorStateIndoorWalk>()));
    _currentActorState = _availableActorStates[0];
    
  3. The rest can be simplified like this:

    if (_currentActorState)
    {
    _currentActorState->MoveForward(Value);
    }

Thanks a lot TTaM!