x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

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 :)

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() {}
 
Product Version: UE 4.10
Tags:
more ▼

asked Jan 07 '16 at 10:12 PM in C++ Programming

avatar image

metamorphium
107 7 13 23

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

2 answers: sort voted first

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!

more ▼

answered Jan 08 '16 at 12:40 AM

avatar image

metamorphium
107 7 13 23

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

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

more ▼

answered Jan 07 '16 at 10:25 PM

avatar image

TTaM
1.7k 81 28 81

avatar image metamorphium Jan 07 '16 at 10:33 PM

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

avatar image TTaM Jan 07 '16 at 10:36 PM

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

avatar image metamorphium Jan 07 '16 at 10:39 PM

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.

avatar image metamorphium Jan 07 '16 at 10:53 PM

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

avatar image TTaM Jan 07 '16 at 11:02 PM

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 );

avatar image metamorphium Jan 07 '16 at 11:45 PM

Still nothing :(

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.

avatar image TTaM Jan 07 '16 at 11:47 PM

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

avatar image metamorphium Jan 08 '16 at 12:36 AM

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

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question