Been working on implementing an entity component architecture for fun and to make some applications with. I’m taking much inspiration from Unity’s component architecture designs, and currently have mimicked a fair few things from it fine. However, the ability to make all references pointing to the same object become nullified, that’s tough to design for. I’ve found out and experimented with a few of the smart pointers available with C++ standard library but nothing has kind of scratched the itch I have. Unique pointers, shared pointers, and weak pointers are the ones I’ve been tinkering with. So far the best way I’ve found to get the functionality I want is to simply make the Instantiate function of the Object factory return a weak_ptr only, and that way the user needs to explicitly handle locking the weak pointer and getting it’s shared pointer. Usability wise though I don’t like it, makes using game objects too cumbersome.
The other idea I’ve had just now is for the copy constructor to be overridden and basically it will keep a copy of all pointers that are pointing to it. Then when destroyed, it will go through and nullify all of them. I experimented with that idea of using a ‘self’ pointer inside the object, but I haven’t figured out how to override the ‘->’ and ‘*’ operators properly yet. If I can make it so I just override those, and have only 1 self pointer, that’ll save on memory, and performance when it comes to destroying game objects by avoiding a 1 to many scenario, instead making it a many to 1 situation. I’ll have to tinker more with that later. The code I made is below.
ObjectFactory.h
#pragma once
class Object;
#include <memory>
#include <vector>
#include "Object.h"
class ObjectFactory
{
public:
static ObjectFactory& const Instance();
std::weak_ptr<Object> Instantiate();
void Destroy(Object* object);
private:
ObjectFactory();
~ObjectFactory();
static ObjectFactory* _instance;
std::vector<std::shared_ptr<Object>> objects;
};
ObjectFactory.cpp
#include "pch.h"
#include "ObjectFactory.h"
ObjectFactory* ObjectFactory::_instance = nullptr;
ObjectFactory & const ObjectFactory::Instance()
{
if (_instance)
return *_instance;
_instance = new ObjectFactory();
}
std::weak_ptr<Object> ObjectFactory::Instantiate()
{
struct make_shared_object_enabler : public Object {};
objects.push_back( std::make_shared<make_shared_object_enabler>() );
return objects[objects.size()-1];
}
void ObjectFactory::Destroy(Object * object)
{
if (object)
{
for (int i = 0; i < objects.size(); ++i)
{
if (object->id == objects[i]->id)
{
//objects.erase(objects.begin() + i);
//delete object;
objects[i].reset();
object = objects[i].get();
objects.erase(objects.begin() + i);
//object = nullptr;
break;
}
}
}
}
ObjectFactory::ObjectFactory()
{
objects.reserve(5);
}
ObjectFactory::~ObjectFactory()
{}
main.cpp
#include <iostream>
#include "Object.h"
#include "ObjectFactory.h"
void printLine(std::string text);
void checkNulled(Object* ptr)
{
std::string output = ptr == nullptr ? "Yes, its null": "No, its not null.";
printLine(output);
}
void printLine(std::string text)
{
std::cout << text << std::endl;
}
int main()
{
std::cout << "Hello World!\n";
std::weak_ptr<Object> hpObj1, hpObj2, hpObj1Ref;
hpObj1 = ObjectFactory::Instance().Instantiate();
hpObj2 = ObjectFactory::Instance().Instantiate();
hpObj1Ref = hpObj1;
hpObj1.lock().get()->name = "Heap Object 1";
hpObj2.lock().get()->name = "Heap Object 2";
printLine(hpObj1.lock().get()->toString());
printLine(hpObj2.lock().get()->toString());
printLine("hpObj1 and ref null status");
checkNulled(hpObj1.lock().get());
checkNulled(hpObj1Ref.lock().get());
ObjectFactory::Instance().Destroy(hpObj1.lock().get());
checkNulled(hpObj1.lock().get());
checkNulled(hpObj1Ref.lock().get());
}