Prevent memory violation when calling overridden functions from derived classes.

Hi All!

I have an abstract class called PlayerBaseState which looks like this:

class ARCHETYPE_API PlayerBaseState : public UObject
{
public:
	PlayerBaseState(AArchetypeCharacter* currentContext, class PlayerStateFactory* playerStateFactory);
	virtual ~PlayerBaseState();
private:
	AArchetypeCharacter* _ctx;
	class PlayerStateFactory* _factory;
protected:
	AArchetypeCharacter Ctx;
	class PlayerStateFactory* Factory;
	void SwitchState(PlayerBaseState* newState);
	class PlayerStateFactory* getFactory();
	AArchetypeCharacter* getCtx();
public:
	virtual void EnterState() = 0;
	virtual void UpdateState() = 0;
	virtual void ExitState() = 0;
	virtual void CheckSwitchStates() = 0;
};

As you can see, this class has 4 pure virtual functions (abstracts). These are overridden in a derived class called PlayerIdleState which looks like this:

class ARCHETYPE_API PlayerIdleState : public PlayerBaseState
{
public:
	PlayerIdleState(AArchetypeCharacter* currentContext, PlayerStateFactory* playerStateFactory);
	virtual ~PlayerIdleState();
	void Log();
public:
	void EnterState() override;
	void ExitState() override;
	void UpdateState() override;
	void CheckSwitchStates() override;
};

However, in my ACharacter code, I get a memory error when I write this :

States = NewObject<PlayerIdleState>(this);
CurrentState = States->Idle();
CurrentState->EnterState();

How can I prevent this ?

I will mention but mostly ignore the missing "U " as the leading character of your UObject derived classes.

when overriding a function that is labeled virtual in the base class it should still be labeled virtual in the derived class

void EnterState() override; 
//becomes
virtual void EnterState() override;

this is one of the ways C++ is a bit dumb, but realistically the C++ compiler should have thrown a red flag
the virtual says “add this to the virtual function table to be resolved at the time the function is called” it is supposed to be a requirement that for any function initially declared as virtual that all decedents of the class that re-declare the function “shall” also be declared as virtual.

in theory adding the virtual ensures the re-declaration/re-definitions are also added to the Virtual Function Table and should clear up the error as the VFT should be utilized directly. additionally if you are going to have no further re-declaration/re-definition of a function on the VFT then instead of “override” you would put “final” which means this is the well “final” re-declaration/re-definition of this function.

1 Like

Gardian206,
Thank you for your response, I didn’t had the “U” before because I didnt’ intend it to be a UOBbject derived class. I’ll update it later.

While I’ve applied the changes you mentionned, it didn’t solve the problem. The error still stands:

memory access violation at 0x0000000074736554.

Maybe I should mention that I get an instance of PlayerIdleState from another UObject-derived class called PlayerStateFactory (yes still no “U” prefix) which looks like this:
PlayerStateFactory.h

#include "CoreMinimal.h"
#include "ArchetypeCharacter.h"
#include "PlayerBaseState.h"
/**
 * 
 */
class ARCHETYPE_API PlayerStateFactory : public UObject
{
public:
	PlayerStateFactory(AArchetypeCharacter& currentContext);
	virtual ~PlayerStateFactory();
private:
	AArchetypeCharacter* _context;
public:
	PlayerBaseState* Idle();
};

PlayerStateFactory.cpp

PlayerStateFactory::PlayerStateFactory(AArchetypeCharacter& currentContext)
{
	_context = &currentContext;
}

PlayerStateFactory::~PlayerStateFactory()
{
}

PlayerBaseState* PlayerStateFactory::Idle()
{
	return NewObject<PlayerIdleState>(this, PlayerIdleState::StaticClass());
}

(I’ve already tested that CurrentState does indeed point to a valid PlayerIdleState address by casting it.)
I’ve noticed that removing the line

CurrentState->EnterState();

compiles fine so the issue comes from this EnterState() function.
As a reminder, this is the sample from where the error appears:

void AArchetypeCharacter::BeginPlay()
{
	// Call the base class  
	Super::BeginPlay();

	// Manage the state machine 
	States = NewObject<PlayerStateFactory>(this); <- Creates the PlayerStateFactory
	CurrentState = States->Idle(); <- Gets a pointer to a new PlayerIdleState here. (PlayerBaseState parent)
	CurrentState->EnterState(); <- Tries to call the most derived EnterState function but gets memory access violation. 
}

The whole architecture depends on these three scripts. {U}PlayerBaseState specifies what a state should look like, {U}PlayerStateFactory gives back new states and PlayerIdleState is a child of {U}PlayerBaseState.

I’ve checked multiple time and asked ChatGPT but couldn’t get a solution.

probably the reason the Compiler/tool-chain is not yelling at you about the “U” is because you are missing UCLASS() and GENERATED_BODY() for the reflection system, but if this class was created as a “blank C++ class” then adding it to the reflection system can be slightly annoying.
by having it be a UCLASS() with GENERATED_BODY() you can give it UPROPERTY() (so that you can examine the states in the Editor) and UFUNCTION() (so that this maybe could be called through blueprints, Events/Functions)

is this EnterState() a pass through to an engine function, or are you doing something separate to the engine’s built in state machine system.
either through logging(UE_LOG() or GEngine->AddOnScreenDebugMessage()) or by stepping through with an IDE debugger does anything about the CurrentState or the members it accesses become null?

a memory access violation is typically:

  • attempting to access a null pointer
  • attempting to access a memory block that has been thread locked
  • attempting to access memory that has not been allocated to the program (the OS should prevent this, and if that failsafe fails it often results in a memory dump)

could you wrap your accesses of States inside a check to see if it was created correctly

if( States = NewObject<PlayerStateFactory>(this))
{
    UE_LOG(LogTemp, Warning, TEXT("States was created %s"), *GetName());
    CurrentState = States->Idle();
    CurrentState->EnterState();
}
else
{
    UE_LOG(LogTemp, Error, TEXT("States was not created %s", *GetName());
}

if an entity is creating its own factory then that doesn’t seam like a factory, but rather a controller: a Factory is typically a static (or near static singleton) entity that is solely responsible for creating things as needed, and then hands them out to the requester, or just puts them into place. typically they do not modify the state of the Thing after it is handed out.

a Controller is either static (near static singleton), or per Entity thing that needs to be controlled (this is probably the most dangerous because if every thing needs its own manager this should either be unified into a static or near static singleton, or let the thing control its own state)

for the static implementation this can be done through creating a Subsystem a C++ exclusive feature with some Additional reading (Unreal-style Singletons with Subsystems · ben🌱ui) in which case you do get Singleton, and by making it a subsystem you match its lifespan to the lifespan of the thing it is a subsystem of, for example if this was to be a subsystem of UWorld (as a UWorldSubsystem) it would have the same lifespan as the UWorld and subsystems are “effectively” not needed to be instantiated manually as long as they are declared appropriately which the compiler/tool-chain will enforce.

the biggest downside to subsystems is the inability to assign data member in the editor to/for them as they are instantiated silently by the Engine (even the ones that exist in the level before PIE will be instantiated from defaults), and are one of the exceptions to instantiated things “needing” actual blueprints (or fake blueprints) to be instantiated.

Well,

I’ve spent the last days trying to get a fix and turns out every class has to derive from UObject for it to work. I read that Unreal has to initiate every class, even abstract ones, so you need to use the PURE_VIRTUAL() and the UCLASS(Abstract) macro to make it work. Those work best when every class derives from UCLASS.
You were right.

EnterState() is my own method, I’m not using the built-in state machine system (there’s one ?)
The class was created correctly but I believe Unreal was preventing my Pure C++ class PlayerIdleState from accessing the memory needed for it to work. Maybe in order to keep it for other UObject instances ?
Kinda weird that you need every single object to derive from UObject to get it working, when do you use pure C++ classes then? When you don’t need any help from the engine?

Anyways, everything works now. GGs.

the built in state machines are implemented for animations (state machines), and “AI” (behavior trees) with a small capability for “fuzzy logic” if need be and they can be designated as the “controller” for a Pawn. you can look a bit here

and

you would use pure C++ for things that you don’t need: data-saving, Garbage collection (you are responsible to allocate and delete memory), Error handling, Type checking/validation, Editor functionality,
or for things where you need straight C and ASM. there are also times it might be useful if you need to do thing that might depend on the standard library a bunch, or for example if you wanted to do your own delegate generation, or threading (these are systems that Unreal has built in)

you can have a pure C++ data object inside a UObject, but you are responsible for creating, maintaining, and deleting it, but you cannot expose it to the editor.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.