I have a Visual Studio 2008 C++ program where I'm populating a std::list
with the addresses of a memory pool.
I have an implementation that works using std::generate
and it's not bad, but it can be a bit slow with large pools of small allocation blocks.
/// fill the allocation list with the memory addresses of each block
struct fill
{
fill( void* start, ulong alloc )
: start_( start ),
alloc_( alloc ),
count_( 0 )
{
};
void* operator()()
{
return ( void* )( ( ulong ) start_ + ( count_++ ) * alloc_ );
}
/// starting address
void* start_;
/// size of the blocks
ulong alloc_;
/// internal counter
int count_;
}; // struct fill
ulong begin = 0; // beginning address
ulong max_size = 0x1000; // maximum memory pool size (4KB)
ulong block_size = 0x20; // size of each memory block (32B)
std::list< void* > memory;
memory.resize( max_size / block_size ); // 128 memory blocks
std::generate( memory.begin(), memory.end(), fill( begin, block_size ) );
I was just wondering if anybody had a faster or more efficient method of fil开发者_如何转开发ling the linked-list.
Thanks, PaulH
Your code passes over the list twice instead of once.
So it might help to define an iterator that returns the addresses, so that everything is done in a single pass:
struct blocks {
void *current;
size_t increment;
blocks(void* start, size_t size = 0) : current(start), increment(size) {}
bool operator==(const blocks &rhs) const { return current == rhs.current; }
bool operator!=(const blocks &rhs) const { return current != rhs.current; }
void *operator*() const { return current; }
blocks &operator++() {
current = (void*)( (char*)current + increment );
return *this;
}
};
std::list<void*> memory(blocks(begin, block_size), blocks(max_size));
(Code not tested, and I've left out some of the stuff you need in order to be a proper iterator - it needs tagging if nothing else, and post-increment is usually welcome.)
Currently it's just a ForwardIterator (or would be, if it was tagged). You could make it a RandomAccessIterator easily enough, but you'd have to give the end iterator the correct size. If you used a container of char(*)[block_size]
instead of a container of void*
, then I think you could just use a boost::counting_iterator<char(*)[block_size]>
to populate it.
Fundamentally, though, std::list
is moderately slow at this. Unless you're going to do insert/remove in the middle (which seems unnecessary for a memory pool free list - if all the blocks are the same size you should be able to always add and remove at the end), you might do better with a vector or deque, or at least with an intrusive linked list.
精彩评论