How would you pass a class type for implementing a spawning factory for object pooling?

The code below works for a very simple implementation of object pooling, but it’s limited to spawning the type statically defined at compile time.

The problems is that I’m having an impossible time figuring out how to make the object pool more flexible/generic. It seems logical to be able to pass the type of any arbitrary subclass of AActor to a function and have it be able to create a container of the arbitrary subclass type, AND additionally spawn the AActors of the same arbitrary subclass type.

One work around would be to create a simple AActor container and cast the objects to their correct type at runtime, but it seems counterintuitive to be casting each actor to it’s appropriate type at runtime when I know exactly what the type will be at compile time; my gut is telling me that this is a problem best solved at compile time.

Another workaround is to create a series of overloaded functions that take a different “dummy pointer” of the subclass type I want spawned and then return with a container of the same subclass type. My gut is again telling me that this is a very error prone and bloated/redundant/brute-forced approach to solving this problem and that there has to be a more elegant solution.

I’m new to UE4 and C++ and I understand that C++ is statically typed, but would this be an application for virtual functions since MyPoolingManager won’t know the type at compile time, but me the programmer knows exactly what it will expect, or am I totally off base with that idea/concept?

Any help is greatly appreciated and thanks in advance!

This is mostly boilerplate code, so stripped out all but important bits, and MyActor is just an empty/generic class.

MyCharacter.h

#pragma once
#include "GameFramework/Character.h"
#include "MyPoolingManager.h"
#include "MyCharacter.generated.h"

UCLASS()
class TESTPROJECT_API AMyCharacter : public ACharacter
{
	GENERATED_BODY()
public:
	AMyCharacter();

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Object Pool")
		AMyPoolingManager* MyActorPool;
//...
};

MyCharacter.cpp

#include "TestProject.h"
#include "MyCharacter.h"
//...
void AMyCharacter::BeginPlay()
{
	Super::BeginPlay();
	
	MyActorPool = ()->SpawnActor<AMyPoolingManager>(AMyPoolingManager::StaticClass());
	MyActorPool->CreatePool(200);
}
//...

MyPoolingManager.h

#pragma once
#include "GameFramework/Actor.h"
#include "MyPoolingManager.generated.h"

USTRUCT(Blueprintable)
struct FSimplePoolStruct
{
	GENERATED_USTRUCT_BODY()
public:
	UPROPERTY(EditAnywhere, Category = "Object Pool")
		TArray<AActor*> PoolArray;

	UPROPERTY(EditAnywhere, Category = "Object Pool")
		int32 Next; // Hold the index of the next available actor

	FSimplePoolStruct() {
		PoolArray.Empty();
		Next = 0;
	}
};

UCLASS()
class TESTPROJECT_API AMyPoolingManager : public AActor
{
	GENERATED_BODY()
	
public:	
	AMyPoolingManager();

	//...

	UFUNCTION()
		void CreatePool(int32 PoolSize);
	
	UFUNCTION()
		AActor* GetActor();

	UPROPERTY(EditAnywhere, Category = "Object Pool")
		FSimplePoolStruct MyPool;
};

MyPoolingManager.cpp

#include "TestProject.h"
#include "MyActor.h"
#include "MyPoolingManager.h"

//...
void AMyPoolingManager::CreatePool(int32 PoolSize)
{
	UWorld* const World = ();
	if (World) {
		MyPool.PoolArray.Reserve(20); // Do the memory allocation up front to avoid multiple allocations while iterating through the loop
		for (int32 i = 0; i < 20; i++){
			MyActor* NewActor = World->SpawnActor<MyActor>(MyActor::StaticClass());
			MyPool.PoolArray.Add(NewActor);
		}
	}
}

AActor* AMyPoolingManager::GetActor(){
	return MyPool.PoolArray[MyPool.Next];
	MyPool.Next++;
}

So you want something like SpawnActor is doing? It’s called templates, but keep in mind templates are not supported by UE4 reflection system

I don’t know what you mean when you say “like SpawnActor is doing.”, because SpawnActor isn’t doing what I need? I’m confused…?

It’s really hard to find any sort of information on pooling, let alone specific to UE4. Outside of the UE4 framework object pooling seems like a great idea and “the right thing to do”, but when you throw in the complexities of how everything interacts within the framework I can begin to see your point.

Yes this was a very simplified version of code for AnswerHub purposes (I even forgot to zero out next when it reached the upperbound on the array as you pointed out), but I thank you for your thorough reply and you’ve given me a lot to think about.

Thanks!

Could you please elaborate a little on what you meant when you said the following,

If other objects in your game world
hold references to the pooled objects,
you are increasing the strain on the
garbage collector.

Ahhhhh… I see said the blind man. That makes perfect sense and is a very good point.

For my own edification, is there any way to optimize the GC by prioritizing certain objects over others for collection, literally putting them at the bottom of the stack possibly even skipping them if needed until a later less “busy” pass, or is an all or nothing process?