A few questions about boost pool

Started by
5 comments, last by Zakwayda 15 years, 8 months ago
I want to write a simple space shooter that will be creating and destroying many objects each frame (enemies, bullets, etc.). I don't want to allocate and free memory many times per frame, so I want to use a memory pool. Fortunately boost has one. I have a couple of questions: 1) I want the syntex to create and destroy objects to be the same whether or not I'm using a memory pool or not, so I created this class:
template <class T>
class PoolObject {
public:
	static void* operator new(size_t size) {
		return memPool.malloc();
	}

	static void operator delete(void *p) {
		memPool.free(p);
	}

private:
	static boost::pool<> memPool;
};

template <class T>
boost::pool<> PoolObject<T>::memPool(sizeof(T));



Now, if I want my Bullet class to use pool allocation, I just derive it from this class:

class Bullet : public PoolObject<Bullet> { ... };

void func() {
    boost::shared_ptr<Bullet> bullet(new Bullet(...));
    b->whatever();
}
My question is, do you see any problems with this or have a better suggestion? 2) When creating a memory pool, you don't specify it's size, so I assume it allocates some fixed amount of memory. But what happens when it runs out of memory? If it will grow the memory like std::vector does, won't that invalidate all the pointers to it? Thanks in advance. [Edited by - Gage64 on August 20, 2008 2:48:19 PM]
Advertisement
Anyone?
Quote:Original post by Gage64
Anyone?
Here's how I'm handling it in my current project (which is similar to yours - an arcade game with objects being created and destroyed frequently):

1. All objects that are likely to be created and destroyed frequently inherit from a 'pooled object' base class.

2. The base class stores a static map of integer values to Boost pool objects.

3. When new or delete is invoked, the requested allocation or deallocation is made using the pool corresponding to the specified size (if no such pool exists yet, it is of course created first).

I plan on reviewing this again at some point, but so far it seems to work fine. If there are any technical problems with this approach, perhaps someone will point them out (I'd be interested to know myself how others handle this problem).
Quote:Original post by jyk
2. The base class stores a static map of integer values to Boost pool objects.

3. When new or delete is invoked, the requested allocation or deallocation is made using the pool corresponding to the specified size (if no such pool exists yet, it is of course created first).


I hadn't thought about that. My code creates a separate memory pool for each class, even if two different classes define objects of the same size, while your code uses just one pool for the latter. Maybe I'll try modifying my code to do the same.

Thanks for the suggestion. [smile]
Quote:Original post by Gage64
Quote:Original post by jyk
2. The base class stores a static map of integer values to Boost pool objects.

3. When new or delete is invoked, the requested allocation or deallocation is made using the pool corresponding to the specified size (if no such pool exists yet, it is of course created first).


I hadn't thought about that. My code creates a separate memory pool for each class, even if two different classes define objects of the same size, while your code uses just one pool for the latter. Maybe I'll try modifying my code to do the same.

Thanks for the suggestion. [smile]
Well, I'm certainly not claiming that it's the optimal solution :) The only real shortcoming I can see though is the map lookup per allocation. (A possible alternative would be to use an array rather than a map, with an entry for each possible allocation size up to the size of the largest object you'd be allocating for. This would make the lookup faster, but would also be less flexible and might require more maintenance.)
One solution I've seen is not to use a memory pool, but just to use an array (or arrays) of pre-allocated objects that have an activation flag. So instead of allocating/de-allocating, you just activate an object with whatever state stuff you would usually pass to the constructor. But maybe you already thought of that and discarded it?
Quote:Original post by theOcelot
One solution I've seen is not to use a memory pool, but just to use an array (or arrays) of pre-allocated objects that have an activation flag. So instead of allocating/de-allocating, you just activate an object with whatever state stuff you would usually pass to the constructor. But maybe you already thought of that and discarded it?
In my project I decided against this approach (and would recommend against using it) for the reason that it runs somewhat counter to the principles of object-oriented design.

One of the key ideas of object-oriented design in C++ is that an object is initialized in its constructor, that any necessary clean up takes place in its destructor, and that at all times in between it is in a valid state. A system that is instead based on initialization and destruction functions is more vulnerable to errors resulting from an invalid or incorrect object state.

These sorts of problems can be worked around, of course, but using good object-oriented design in the first place obviates the need for such workarounds. Also, as I understand it at least, the Boost Pool library (or any similar library) will do something like what you describe (return an object from an 'unused slot') under the hood anyway, with the added benefit that a) the work is already done for you, and b) you are free to utilize good OO practices while still benefitting from pooled allocation.

This topic is closed to new replies.

Advertisement