Using my new object pooling system

So I sat down today to start to actually use the new object pooling system I created last time. I realised pretty quickly that my ComponentPool was poorly named since I also wanted to pool my Bullets (which are GameObjects).

Also, my BulletObjects are currently responsible (during their Update function) for checking to see if they need to mark themselves as inactive. The BulletManager then polls each BulletObject to see if it’s been listed as inactive. However with my new object pooling the BulletManager doesn’t actually have access to the array of BulletObjects – just the BulletObject pool that I added.

The object pool class also stores an array of bools to keep track of which elements are active. So, what is the best way for my BulletObject pool to work out that a BulletObject is no longer active?

Some quick thoughts – I could set up some sort of Visitor pattern for the object pool so I can send custom functions in? But the Visitor pattern has always felt rather messy and a bit like it’s cheating OOP. Then perhaps an Event class that acts similar to Events in C#? (Hey, I work in C# all day). This example looks promising. The the BulletManager could handle the event and call the object pool’s Destroy method for the BulletObject that triggered the event.

I think I’m leaning towards the Event implementation, but I’d be curious to hear other ideas!

Object pools, variadic templates and reference forwarding

Right, so after my last post it seemed pretty clear that I need to overhaul how I manage the creation and deletion of my components, and that object pooling looked like the best way to do that. So I referred back to Cameron’s comment from ages ago and started to write some object pooling classes for each of my components. However I very quickly worked out that I’d be writing the same thing over and over again.

So, clearly I needed to write a templated version. Once again Cameron had an amazing example that I could have a look at. I decided it was quite a bit more complex than what I needed for now, so I started making a simplified version. I can’t believe how much I’d forgotten about templates – it’s actually a bit embarrassing. It’s really driving home how much more I should be practising on my own C++ projects if I don’t want to forget everything I’ve ever learned while I am stuck using C# at work every day.

I converted the original PhysicsComponentPool I’d started to write into a ComponentPool pretty quickly. I had written a “create” function that accepted the parameters needed to initialise a PhysicsComponent so that I could do just that in the function and return the newly activated and initialised PhysicsComponent. Converting this into a more generic function stumped me for a while.

My options were:

  • write a number of overloaded “create” functions that would suit every component type I had made.
  • leave the responsibility of initialisation up to the class that called the “create” function. The create function would then just be responsible for activating a component and maintaining the state of the object pool.
  • work out how to send variable parameters into my “create” function and how to set up the “init” functions of my components to work with this.

The latter idea was based on Cameron’s “new_object” function in the FixedObjectPool class, but there was a lot going on in his implementation that I didn’t understand and it didn’t quite seem to fit what I wanted. So I did some research to both understand Cameron’s implementation and to find a solution to my problem.

I first worked out that template is an implementation of variadic templates which were introduced in C++11. Variadic templates allow me to send any number of parameters of any type(s) into a function, like so:

template<typename T>
template<typename... Args>
T* ComponentPool::Create(Args... args)
{

}

So, that’s great! Now I can just send these arguments along to the Init function for the component like this:

template
template
T* ComponentPool::Create(Args... args)
{
    for (unsigned int i = 0; i < m_iSize; ++i)
    {
        if (m_pActive[i] != true)
        {
            m_pComponent[i].Init(args);
            m_pActive[i] = true;
            return &m_pComponent[i];
        }
    }
    return nullptr;
}

Uh, no. That does not compile: argserror.

So I then looked at how to expand variadic parameters. It was in a recursive-like fashion where each recursive call to the function unpacked one more argument. Not exactly what I wanted. I just wanted to send ALL the arguments along to my init function. I took another look at Cameron’s example and discovered that he was using something called std::forward. Let’s try that:

template
template
T* ComponentPool::Create(Args... args)
{
    for (unsigned int i = 0; i < m_iSize; ++i)
    {
        if (m_pActive[i] != true)
        {
            m_pComponent[i].Init(std::forward(args)...);
            m_pActive[i] = true;
            return &m_pComponent[i];
        }
    }
    return nullptr;
}

That worked perfectly! I still didn’t really know what std::forward was really doing though. The documentation online was not very easy to understand, but I found a great blog post that made things a bit clearer. std::forward returns an r-value reference to its parameter and placing the ellipses (…) outside of the call to std::forward means that std::forward will be called for each argument in args, which effectively unpacks args while also preserving the lvalue or rvalue status of the arg.

Preserving an argument’s lvalue or rvalue nature is known as perfect forwarding. It’s explained quite well in the post I linked above, as well as in this stack overflow post, so I’m not going to try and re-explain it.

After reading those two posts it was clear that my Create function was not forwarding references properly, so I needed to change it a bit:

template<typename... Args>
T* Create(Args&&... args);

Much better 🙂

Midway through that research I did realise that std::forward wasn’t actually responsible for unpacking the argument list. It was the ellipses. So just having:

m_pComponent[i].Init(args...);

also worked the way I wanted. However it was probably a good idea to preserving the references (though I did try the non forwarded version with both arguments that I had thought were lvalues and arguments I thought were rvalues and everything worked correctly. Perhaps perfect forwarding is just to prevent lvalue copy inefficiencies?)

As always you can have a look at my code on github (still in the component-pattern-setup branch for the moment).

Thanks for all the responses to my last post – they gave me a lot to think about.