overloading new and delete C++ for tracking memory allocations
I need help in understanding the code snipped below...allocate is a function that would be called by the overloaded new operator to allocate memory. I am having problems trying to understand the following casts in particular:
*static_cast<std::size_t*>(mem) = pAmount; //please explain?
return static_cast<char*>(mem) + sizeof(std::size_t); //?
and..
// get original block
void* mem = static_cast<char*>(pMemory) - sizeof(std::size_t); //?
the code is shown below:
const std::size_t allocation_limit = 1073741824; // 1G
std::size_t totalAllocation = 0;
void* allocate(std::size_t pAmount)
{
// make sure we're within bounds
assert(totalAllocation + pAmount < allocation_limit);
// over allocate to store size
void* mem = std::malloc(pAmount + sizeof(std::size_t));
if (!mem)
return 0;
// track amount, return remainder
totalAllocation += pAmount;
*static_cast<std::size_t*>(mem) = pAmount;
return static_cast<char*>(mem) + sizeof(std::size_t);
}
void deallocate(void* pMemory)
{
// get original block
void* mem = static_cast<char*>(pMemory) - sizeof(std::size_t);
// track amount
std::size_t amount = *static_cast<std::size_t*>(mem);
totalAllocation -= pAmount;
// free
s开发者_StackOverflow中文版td::free(mem);
}
The allocator keeps track of the size of allocations by keeping them along with the blocks it serves to client code. When asked for a block of pAmount
bytes, it allocates an extra sizeof(size_t)
bytes at the beginning and stores the size there. To get to this size, it interprets the mem
pointer it gets from malloc
as a size_t*
and dereferences that (*static_cast<std::size_t*>(mem) = pAmount;
). It then returns the rest of the block, which starts at mem + sizeof(size_t)
, since that is the part that the client may use.
When deallocating, it must pass the exact pointer it got from malloc
to free
. To get this pointer, it subtracts the sizeof(size_t)
bytes it added in the allocate
member function.
In both cases, the casts to char*
are needed because pointer arithmetic is not allowed on void
pointers.
void* allocate(std::size_t pAmount)
allocates pAmount of memory plus space to store the size
|-size-|---- pAmount of memory-----|
^
|
"allocate" will return a pointer just pasted the size field.
void deallocate(void* pMemory)
will move the pointer back to the beginning
|-size-|---- pAmount of memory-----|
^
|
and free it.
1.)
std::size_t mySize = 0;
void * men = & mySize;
// same as: mySize = 42;
*static_cast<std::size_t*>(mem) = 42;
std::cout << mySize;
// prints "42"
2.)
`return static_cast<char*>(mem) + sizeof(std::size_t);
// casts void pointer mem to a char* so that you can do pointer arithmetic.
// same as
char *myPointer = (char*)mem;
// increment myPointer by the size of size_t
return myPointer + sizeof(std::size_t);
3.)
`void* mem = static_cast<char*>(pMemory) - sizeof(std::size_t);`
// mem points size of size_t before pMemory
In order to know how much memory to clean up when you delete it (and provide some diagnostics) the allocator stores off the size in extra allocated memory.
*static_cast(mem) = pAmount; //please explain?
This takes the allocated memory and stores the number of allocated bytes into this location. The cast treats the raw memory as a size_t
for storage purposes.
return static_cast(mem) + sizeof(std::size_t); //?
This moves forward past the size bytes to the actual memory that your application will use and returns that pointer.
void* mem = static_cast(pMemory) - sizeof(std::size_t); //?
This is taking the block previously returned to the user and advancing back to the "real" allocated block that stored the size earlier. It's needed to do checks and reclaim the memory.
the cast is needed in order to get the proper offset since void* is not a type with a size.
when you write
return static_cast(mem) + sizeof(std::size_t);
the pointer is cast to a char* before the offset bytes is added.
ditto subtract when deallocating.
精彩评论