Crash involving TArray, Custom Classes, and NewObject

I am currently developing a class that manages abilities for different classes of characters. Different characters will have different abilities, and MyAbilityManager is acting as the authority.

I am getting clean compilations but my game is crashing when I press the input key. Here is the code that is relevant to my issue.

The log reads “Access violation code c0000005 (first/second chance not available)” It references this line in AbilityManager.cpp “return Ability[AbilityNumber];”

The only thing I can think of is maybe I didn’t initialize the Ability array properly in the constructor and I’m returning a null reference when the call to GetAbility(…) is made. Is there another place I should be initializing this array or perhaps another class that is better to inherit from than UObject?

***MyCharacter.h

#include "AbilityManager.h"

...

template<int Index>
void ToggleAbility() { ToggleAbility(Index); }; // Template function for Input

void ToggleAbility(int AbilityNumber);

UAbilityManager* AbilityManager;

***MyCharacter.cpp

void AMyCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
   ...
   InputComponent->BindAction("TogglePrimaryAbility", IE_Pressed, this, &AMyCharacter::ToggleAbility<0>);
   InputComponent->BindAction("ToggleSecondaryAbility", IE_Pressed, this, &AMyCharacter::ToggleAbility<1>);
   ...
}

void AMyCharacter::ToggleAbility(int AbilityNumber)
{
   AbilityManager->ToggleAbility(AbilityNumber);
}

***AbilityManager.h

#pragma once

#include "Ability.h"
#include "AbilityManager.generated.h"

class Ability;

UCLASS(Within = MyCharacter)
class SHOOTERGAME_API UAbilityManager : public UObject
{
	GENERATED_UCLASS_BODY()

public:

   ...
	UFUNCTION(exec)
		UAbility* GetAbility(uint8 AbilityNumber);

	void ToggleAbility(int AbilityNumber);

	UPROPERTY()
		TArray<class UAbility*> Ability;

   ...
};

***AbilityManager.cpp

UAbilityManager::UAbilityManager(const class FObjectInitializer& ObjectInitializer)
{
	UAbility* AbilityToAdd = NewObject<UAbility>(UAbility::StaticClass());

	Ability.AddUnique(AbilityToAdd);
}

void UAbilityManager::ToggleAbility(int AbilityNumber)
{
	UAbility* AbilityToToggle = GetAbility(AbilityNumber);

	if (AbilityToToggle->IsActive())
		AbilityToToggle->Deactivate(); // Implementation currently set to display a debug message, nothing else

	else if (CanActivate(AbilityNumber))
		AbilityToToggle->Activate(); // Implementation currently set to display a debug message, nothing else
}

UAbility* UAbilityManager::GetAbility(uint8 AbilityNumber)
{
	return Ability[AbilityNumber]; // Log says THIS is the line of code causing the editor to crash when I make a call to "TogglePrimaryAbility" in MyCharacter.  
}

bool UAbilityManager::CanActivate(int AbilityNumber)
{
	UAbility* AbilityToCheck = GetAbility(AbilityNumber);

	if (AbilityToCheck->IsActive())
		return false;
	else
		return true;
}

…or you trying to access element that does not exist, which will crash when you do that. If you pre-init elements call Init(Number of elements), but do that outside constructor. But if i would you, i would check if ability item exists before returning and controllably return nullptr if there none.

If UE4 detect something that can cause crash, or it do controlled crash by detecting anomaly or some error, it usually leave message what went wrong before crash happens, and if i’m not mistaken it should do that in this case, as [] operator works same way as function and TArray knows what you trying to access.

So should I use Ability.Init(blahblahblah) inside of PostInitProperties? Under what function should I initialize that array? Why can’t these be initialized in the constructor?

Any as long it’s not constructor or constructor called so PostInitProperties should do.

Alright, I took the code out of the constructor, it’s now completely empty. Here is my PostInitProperties() and it is now crashing the editor with the same access violation, but this time it’s crashing when trying to use the AddOnScreenDebugMessage. I’m really thinking that I’m not initializing the TArray properly and it’s causing me to use a nullptr, crashing the engine. I can do all of the exception handling code later.

Here is what my PostInitProperties() looks like:

void UAbilityManager::PostInitProperties()
{
	Super::PostInitProperties();

	UAbility* AbilityToAdd = NewObject<UAbility>(UAbility::StaticClass());

	Ability.Init(AbilityToAdd, 1);

	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("AbilityNum: %f"), Ability.Num())); // Crash happening here
}

GEngine is NULL?

Try logging to output instead:

UE_LOG(LogTemp, Display, TEXT("AbilityNum: %f"), Ability.Num());

No, no. GEngine is not null. If I comment out the first lines where I declare and define AbilityToAdd then call the Init function on my Ability TArray and then change the line for the debug message to “GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT(“Test”)));” Everything loads just fine.

Something is wrong with the TArray itself and I can’t think of what it might be. Even trying to call the .Num() function on an uninitialized TArray shouldn’t crash the engine.

Also:

DEPRECATED(4.8, "Init is deprecated - please use SetNumUninitialized(Number) instead.")

For pointer types I typically end up with code that looks like this:

array.Reset(expectMaxSize);
array.Add(pMyPointerTothingy);
  1. If you put a breakpoint in the code and look at the variables in a watch window what do you see?

  2. Got any output?

And do you need the UFUNCTION(exec)? This seems to enable the function as a console command.