Pointer to subobject gets invalid after creation

Hi! I am making a class derived from Character. This class creates an instance of a “Cover Helper” Class (derived from Scene Component) using createDefaultSubobject(). The problem is that this Cover Helper instance becomes invalid for some reason which hinders me from using it’s function findCoverNear(). I checked if it is valid using IsValid() on several different occasions, in the constructor, in BeginPlay() and in Tick(). I also check via Blueprints through a Blueprint class derived from my custom character class. Only the check inside the constructor comes back as valid. I don’t understand how this can happen! It have been looking around the internet but can’t seem to find any solution, help would be much appreciated! source and header files pasted below

my custom character class (.cpp):

#include "AdvancedCharacter.h"


// Sets default values
AAdvancedCharacter::AAdvancedCharacter(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer.SetDefaultSubobjectClass<UAdvCharMovementComponent>(ACharacter::CharacterMovementComponentName))
{
	if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Yellow, TEXT("test")); }
	//MovementComponent = Cast<UAdvCharMovementComponent>(GetMovementComponent());
	CoverHelper = CreateDefaultSubobject<UCoverHelper>(TEXT("CoverHelperObject"));
	CoverHelper->SetupAttachment(RootComponent);
	if (IsValid(CoverHelper))
	{
		if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Blue, TEXT("isValid")); }
	}
	else {
		if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Blue, TEXT("notValid")); }
	}
	
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AAdvancedCharacter::BeginPlay()
{
	Super::BeginPlay();
	if (IsValid(CoverHelper))
	{
		if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, TEXT("isValid")); }
	}
	else {
		if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, TEXT("notValid")); }
	}
}

// Called every frame
void AAdvancedCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	
	if (IsValid(CoverHelper))
	{
		if (GEngine) { GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Red, TEXT("isValid")); }
	}
	else {
		if (GEngine) { GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Red, TEXT("notValid")); }
	}
}

// Called to bind functionality to input
void AAdvancedCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

}
UCoverHelper *AAdvancedCharacter::GetCoverHelper()
{
	return CoverHelper;
}

custom character class (.h)

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "AdvCharMovementComponent.h"
#include "CoverHelper.h"
#include "AdvancedCharacter.generated.h"

UCLASS()
class ADVCHARPROJ_API AAdvancedCharacter : public ACharacter
{
	GENERATED_UCLASS_BODY()

	

public:
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly ,BlueprintGetter = "GetCoverHelper")
		class UCoverHelper *CoverHelper;

	UFUNCTION(BlueprintGetter)
		UCoverHelper *GetCoverHelper();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
	
	UAdvCharMovementComponent *MovementComponent;
	
};

CoverHelper.cpp:

#include "CoverHelper.h"


// Sets default values for this component's properties
UCoverHelper::UCoverHelper()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = true;
	//isActive = false;
	CharacterOwner = this->GetAttachmentRootActor();
	//UAdvCharMovementComponent *MovementComponent = Cast<UAdvCharMovementComponent>(CharacterOwner->GetMovementComponent());
	// ...
}


// Called when the game starts
void UCoverHelper::BeginPlay()
{
	Super::BeginPlay();

	// ...
	
}


// Called every frame
void UCoverHelper::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// ...
}

bool UCoverHelper::FindCoverNearest(float range) 
{
	bool validCover = false;
	FVector startLocation = CharacterOwner->GetActorLocation();
	FHitResult prevHit;
	FCollisionQueryParams CollisionParams;
	CollisionParams.AddIgnoredActor(CharacterOwner);
	for (int i = 0; i < 8; i++) {
		if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Yellow, TEXT("for")); }
		FRotator rot = FRotator(0, i * 45,0);
		FHitResult Hit;
		FVector direction = FVector(range, 0, 0);
		FVector endLocation = startLocation + rot.RotateVector(direction);
		validCover = GetWorld()->LineTraceSingleByChannel(Hit, startLocation, endLocation, ECollisionChannel::ECC_WorldDynamic, CollisionParams);
		DrawDebugLine(GetWorld(), startLocation, endLocation, FColor::Green, true, -1, 0, 2.f);
		if (validCover) {
			if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Yellow, TEXT("validCover")); }
			float dist = Hit.Distance;
			if (prevHit.bBlockingHit) {
				prevHit = Hit;
			}
			else if (Hit.Distance < prevHit.Distance) {
				prevHit = Hit;
			}
		}
		
	}
	return validCover;
}
bool UCoverHelper::FindCoverDirectional(FQuat direction, float range)
{
	bool validCover = false;
	//raycast logic
	return validCover;
}

void UCoverHelper::SetIsActive(bool b) 
{
	//isActive = b;
}

bool UCoverHelper::GetIsActive()
{
	return false;
}

CoverHelper.h:

#pragma once

#include "CoreMinimal.h"
#include "EngineGlobals.h"
#include "Components/SceneComponent.h"
#include "AdvancedCharacter.h"
#include "DrawDebugHelpers.h"
#include "CoverHelper.generated.h"


UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class ADVCHARPROJ_API UCoverHelper : public USceneComponent
{
	GENERATED_BODY()

public:	
	// Sets default values for this component's properties
	UCoverHelper();
	AActor *CharacterOwner;
protected:
	// Called when the game starts
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

	UFUNCTION(BlueprintCallable)
	bool FindCoverNearest(float range);
	bool FindCoverDirectional(FQuat direction, float range);
	void SetIsActive(bool b);
	bool GetIsActive();
		
	
};

I haven’t looked in-depth through your code but…

Shouldn’t line 18 from your “custom character class (.h)” read:

UCoverHelper *CoverHelper;

…without the class declaration?

It probably should. I added “class” because I read it somewhere and it fixed an error I had. Now when I remove it it doesn’t seem to make a difference.

Perhaps the problem is not in the creation of the subobject but on the IsValid() check. IsValid() is not just a null check, it has a couple of extra stuff.

Try using a normal if check instead of your IsValid() assertion.

That does not seem to be the problem. The normal if check also returns a nullpointer

What do you mean by “it doesn’t seem to make a difference”?

You removed the “class” keyword. The code compiled. IsValid(CoverHelper) returns:

  • true in AAdvancedCharacter() - the constructor
  • false in BeginPlay()
  • false in Tick()

Is all this correct?

P.S. I would really love to see where you read about this kind of declaration. What problem did it solve?

What I mean is that no issues were solved or caused by removing the class declaration. The code ran the same.
Yes all that is correct.
I can’t remember where I read it. Since I have been having alot of issues with the engine lately I have been looking a little bit all over the place for solutions. I think it was some sort of “undefined identifier” compiler error but I am not sure.

I got deeper in this bizarre declaration and it turns out it is called Elaborated Type Specifier.

You don’t need it but it should not affect the execution. Something else is nullifying your pointer.

Add a Data Breakpoint to your pointer and see what clears it. It might be a blueprint or some other part of your code.

I tried adding a Data Breakpoint to the CoverHelper variable but when it breaks it says “Source not Available” I have never used the Debugger in Unreal before and I don’t know how to solve this.

Well I had to try it out…

It runs fine on my build (4.20.1):

249662-valid.png

Of course I had to replace your UAdvCharMovementComponent with the default UCharacterMovementComponent but I did nothing more than that. (copy/pasted all other code)

My best guess is that you nullify your pointer in your UAdvCharMovementComponent or some other class that has access to it.

The code posted on the question is fine.

hmm that’s wierd I don’t think there is any other class that has access to the CoverHelper class. I tried replacing the UAdvCharMovementComponent with the default UCharacterMovementComponent class, like you, but no luck. This is really funky, should I try reinstalling the engine or something? This project was migrated from 4.18 to 4.20 could that have an affect?

I have no idea if the build has anything in common but it rarely does.

Try it out on a new project with the default movement component and tell us how it went.

It takes 30 min at most.

Hi I tried what you said and it seems that it is the line UFUNCTION(BlueprintCallable) in Coverhelper.h before the findCoverNearest method that somehow nullifies my coverhelper. I came to this conclusion by adding one small part of code at a time and se when the result gives me an invalid result. Once it got invalid I had to undo the change in code and close the editor and delete the generated project files and rebuild the project in order to get valid again. So something fishy seems to happen in the binaries ,when I add that line of code, that is not resolved after a hot reload.

It can’t believe UFUNCTION is the problem.

I am starting to think that you don’t attach your CoverHelper correctly in AdvancedCharacter.cpp and it’s swiped up by the garbage collector. (unattached components are automatically deleted)

I don’t see where RootComponent is set. The variable itself comes from AActor but its content is constructed in ACharacter.

Can you check if RootComponent is valid in AdvancedCharacter.cpp before attaching CoverHelper to it?

The RootComponent seems to be valid before and after I attach the CoverHelper. What content excactly needs to be constructed?

The RootComponent of an ACharacter is an UCapsuleComponent. Your class is derived from it so the constructor of ACharacter should create the capsule and assign it to the root.

Can you check IsValid(CoverHelper->GetAttachParent()) instead of RootComponent?

(long shot but I’m running out of ideas)

As far as I can see you are missing a lot UPROPERTY() tags above pointers. That could mean that the CoverHelper instance is deleted by the GC as a result of the references. Rule of thumb always mark your pointers as UPROPERTY always.

You can read more about garbage collection here:

It’s shorten version for standard forward declaration.
Simply instead of writing:

class Foo;

Foo* SomeVariable;

you are just typing:

class Foo* SomeVariable;

It helps us because we don’t need to include whole header file to another header.
C++ needs to know size of the member and if it’s a pointer, the size will be always same on a specific platform!
And why is that so useful you may ask, because it prevents us from circular dependencies.

At the end I thought that it could be a GC cleanup but I never knew that UPROPERTY() is so important.

Thanks for the useful link. I hope @Kurtaa1 tries this.

It randomly started working again, I don’t know how long it will last though since Unreal has been behaving very strange lately. I think that this might have been the issue though( it seems like the most reasonable explaination). Thank you very much for the article. It gave me much better insight to C++ with Unreal :slight_smile: