TArray Randomly getting Deallocated

Background

I have two simple UFUNCTIONS in a class which holds a TArray:

GetScheduleItemAt(int arrayloc) // gets the items at an array location for Blueprints
GetSize() // simply returns the TArray.Num

I go ahead and insert 24 class pointers into the array at BeginPlay and then every frame I call GetSize() to make sure the TArray size > 0, and if so, I get a specific item at a location.

However, after the game runs for about 1 minute (consistently this happens every time), GetSize() returns -572662307 instead of 24, making me assume it’s been deallocated.

Does anyone know why this might be? I have tried with the TArray both as a UPROPERTY() and not, so it appears to make little difference.

Here is the class and its header file:

.cpp:

#include "Warlock.h"
#include "Schedule.h"


// Called when the game starts or when spawned
void ASchedule::BeginPlay()
{
	Super::BeginPlay();

	Schedule = TArray<UScheduleItem*>();
	Schedule.Reserve(24);
}

void ASchedule::InsertScheduleItem(UScheduleItem* si)
{
	int start_hour = si->GetStartHour();
	int end_hour = si->GetEndHour();

	if (start_hour < MIN_HOUR_IN_DAY || start_hour > MAX_HOUR_IN_DAY)
		return;
	if (end_hour < MIN_HOUR_IN_DAY || end_hour > MAX_HOUR_IN_DAY)
		return;

	for (int i = start_hour; i < end_hour; i++)
		Schedule.Insert(si, i);

}

void ASchedule::PrintDebug()
{
	UE_LOG(LogTemp, Warning, TEXT("Schedule Printing: "));

	for(UScheduleItem* si : Schedule)
	{
		const UEnum* temp = FindObject<UEnum>(ANY_PACKAGE, TEXT("CitizenState"));
		UE_LOG(LogTemp, Warning, TEXT("Task: %s, StartHour: %d, EndHour: %d"), *(temp ? temp->GetNameStringByIndex((int32)si->task) : TEXT("Invalid Enum")), si->GetStartHour(), si->GetEndHour());
	}
}

UScheduleItem* ASchedule::GetScheduleItemAt(int loc)
{
	return Schedule[loc];
}

int ASchedule::GetSize()
{
	return Schedule.Num();
}

.h:

#pragma once

#include "GameFramework/Actor.h"
#include "ScheduleItem.h"
#include "Schedule.generated.h"


const int MIN_HOUR_IN_DAY = 0;
const int MAX_HOUR_IN_DAY = 24;


/**
 * 
 */
UCLASS()
class WARLOCK_API ASchedule : public AActor
{
	GENERATED_BODY()
	
public:
	void InsertScheduleItem(UScheduleItem* si);
	void PrintDebug();
	UScheduleItem* GetScheduleItemAt(int loc);
	int GetSize();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
private:
	UPROPERTY()
		TArray<UScheduleItem*> Schedule;
	
};

you are only reserving 24 pointers in your array. but your are never setting the ptr to a live object.

You have to do something like the following;
for( int32 Index = 0; Index < 24; Index++)
{
UScheduleItem* NewSchedule = NewObject(this, USchedualeItem::StaticClass());
Schedule.Add(NewSchedule);
}

you dont have to create a new instance of the TArray object to begin with.

Well that is what InsertScheduleItem does correct? I call that (function above) here:

#include "Warlock.h"
#include "Clerk.h"


AClerk::AClerk()
{

}

void AClerk::BeginPlay()
{
	Super::BeginPlay();

	citizen_class = CitizenClass::clerk;
	clerk_schedule = NewObject<ASchedule>();

	// basic clerk schedule
	InitSchedule();
}

void AClerk::InitSchedule()
{
	UScheduleItem* sleep = NewObject<UScheduleItem>();
	sleep->Init(0, 8, CitizenState::sleeping);
	UScheduleItem* eat1 = NewObject<UScheduleItem>();
	eat1->Init(8, 9, CitizenState::eating);
	UScheduleItem* work1 = NewObject<UScheduleItem>();
	work1->Init(9, 13, CitizenState::working);
	UScheduleItem* eat2 = NewObject<UScheduleItem>();
	eat2->Init(13, 14, CitizenState::eating);
	UScheduleItem* work2 = NewObject<UScheduleItem>();
	work2->Init(14, 18, CitizenState::working);
	UScheduleItem* eat3 = NewObject<UScheduleItem>();
	eat3->Init(18, 19, CitizenState::eating);
	UScheduleItem* work3 = NewObject<UScheduleItem>();
	work3->Init(19, 24, CitizenState::working);


	clerk_schedule->InsertScheduleItem(sleep);
	clerk_schedule->InsertScheduleItem(eat1);
	clerk_schedule->InsertScheduleItem(work1);
	clerk_schedule->InsertScheduleItem(eat2);
	clerk_schedule->InsertScheduleItem(work2);
	clerk_schedule->InsertScheduleItem(eat3);
	clerk_schedule->InsertScheduleItem(work3);

	clerk_schedule->PrintDebug();

}


CitizenState AClerk::RetrieveScheduleTask(int hour)
{
	return clerk_schedule->GetScheduleItemAt(hour)->task;
}

bool AClerk::IsInitialized()
{
	UE_LOG(LogTemp, Warning, TEXT("Size is: %d"), clerk_schedule->GetSize());

	return clerk_schedule->GetSize() > 0;
}

I think you have to add an outer to your NewObject.

auto NewSchedule = NewObject(this);

What do you mean ‘add an outer’? I don’t quite see how that fits into my code.