I am trying to implement a custom memory manager and I am wondering if there is a better way to implement this function, as when I am asked about void pointer arithmetic, several people thought that if I had a void* in C++, something was very wrong.
// allocates a page of memory.
void ObjectAllocator::allocatePage()
{
//if(OAStats_.PagesInUse_ >= Config_.MaxPages_)
//throw exception
void* buffer = ::operator new(OAStats_.PageSize_); // allocate memory, no constructor call.
// =============== Setup the PageList_ ===============
GenericObject* pNewNode = ::new(buffer) GenericObject(); // Construct GenericObject for the pagelist.
pNewNode->Next = PageList_->Next; // pNewNode points to wherever PageList_ pointed to.
PageList_->Next = pNewNode; // PageList_ points to pNewNode
pNewNode = NULL; // dont need this handle anymore
buffer = static_cast<char*>(buffer) + sizeof(GenericObject); // move pointer to point after the generic object.
// =============== Setup the FreeList_ ===============
for(int i=0;i<Config_.ObjectsPerPage_;++i)
{
static GenericObject* pPreviousNode = NULL; // static variable to hold the previous node
pNewNode = ::new(buffer) GenericObject(); // Construct GenericObject for the freelist.
pNewNode->Next = pPreviousNode;
pPreviousNode = pNewNode;
buffer = static_cast<char*>(buffer) + OAStats_.ObjectSize_; // move pointer by ObjectSize.
++OAStats_.FreeObjects_;
}
FreeList_->Next = pNewNode;
++OAStats_.PagesInUse_;
++OAStats_.Allocations_;
}
If you need a block of memory for for storing a string (8-bit ANSI), it makes sense to declare a pointer to that buffer as char and operate on it.
In your case, you need a block of memory that is a 'blob', it has no inherent type, so you correctly chose void* to represent that blob.
Now you need to increment that pointer by the size of some object. You cannot perform arithmetic on a void pointer for obvious reasons, so what do you do? Cast it. There is no shame in that.
In C++, on raw bytes, use a char*, and don't think any less of yourself. It's The Right Thing To Do (tm). Especially if you wrap it in a higher level construct, like you have.
There's nothing inherently wrong with the void*. However, what we often see is people coming from C who overuse void* when they should do something else. If you're managing raw memory blobs, then a void* is perfectly appropriate. However, there's rarely any other reason to do it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With