This is programmed in Visual Studio 2019 with the C++17 feature set.
The intent with this code is to be able to create memory blocks of the specified alignment and size, so as to have contiguous cache-friendly memory and to only do one malloc and free for the whole block. Is there something wrong or missing from this implementation so that it would effectively fulfill its purpose?
MemoryBlock.h
#pragma once
class MemoryBlock
{
private:
void* p_rawMem;
void* p_currentMemLocation;
size_t p_currentMemLocationOffset;
size_t p_totalMemSize;
size_t p_remainingMemSize;
size_t p_alignment;
void *p_lastMemByteLocation;
void p_addCurrentMemLocation(size_t delta);
public:
MemoryBlock(size_t size, size_t alignment);
void* getMemoryWith(size_t size, size_t alignemnt);
~MemoryBlock();
};
MemoryBlock.cpp
#include <memory>
#include <stdexcept>
#include <cmath>
#include <assert.h>
#include "MemoryBlock.h"
void MemoryBlock::p_addCurrentMemLocation(size_t delta)
{
if (delta == 0) {
return;
}
p_currentMemLocationOffset += delta;
assert((p_currentMemLocationOffset) <= p_totalMemSize);
p_remainingMemSize -= delta;
if (p_remainingMemSize == 0) {
p_currentMemLocation = p_lastMemByteLocation;
}
else {
p_currentMemLocation = static_cast<void*>(static_cast<char*>(p_currentMemLocation) + delta);
}
}
MemoryBlock::MemoryBlock(size_t size, size_t alignment):
p_rawMem(_aligned_malloc(size, alignment)),
p_currentMemLocation(p_rawMem),
p_currentMemLocationOffset(0),
p_totalMemSize(size),
p_remainingMemSize(size),
p_alignment(alignment),
p_lastMemByteLocation(static_cast<void*>(static_cast<char*>(p_rawMem) + (size - 1)))
{
}
void* MemoryBlock::getMemoryWith(size_t size, size_t alignment)
{
if (size > p_totalMemSize) {
throw std::bad_alloc();
}
if (size == 0) {
throw std::invalid_argument("size must be greater than 0");
}
if (alignment == 0 || (alignment &(alignment-1))!= 0) {//checks it alignment is power of 2
throw std::invalid_argument("alignment should be a power of 2.");
}
if (alignment > p_alignment) {
throw std::invalid_argument("alignment requirement is greater than the memory block alignment.");
}
if (size > p_remainingMemSize) {
return nullptr;
}
if (p_totalMemSize == p_remainingMemSize) {
p_addCurrentMemLocation(size);
return p_rawMem;
}
p_addCurrentMemLocation((std::ceil(p_currentMemLocationOffset/(double)alignment)*alignment)-p_currentMemLocationOffset);
void* retVal = p_currentMemLocation;
p_addCurrentMemLocation(size);
return retVal;
}
MemoryBlock::~MemoryBlock()
{
_aligned_free(p_rawMem);
}
main.cpp
int main()
{
MemoryBlock memBlock(1024,1024);
int *memBlockIntPtr = new(memBlock.getMemoryWith(sizeof(int),alignof(int))) int(1);
std::cout << *memBlockIntPtr << std::endl;
constexpr size_t intArrSize = 4;
int *memBlockIntArrPtr = static_cast<int*>(memBlock.getMemoryWith(sizeof(int)*intArrSize, alignof(int)));
for (size_t i = 0; i < intArrSize; i++)
{
new (&memBlockIntArrPtr[i]) int(i);
}
for (size_t i = 0; i < intArrSize; i++)
{
std::cout << memBlockIntArrPtr[i] << std::endl;
}
return 0;
}
I also ask you if the usage of the code is correct in the main function, and if I'm handling the void pointers adequately in both single-variable and array cases. If not, of course, please correct me with an explanation. Say if I'm doing main, specifically, correctly or the whole thing- and if not, make it clear why. Also suggest if I should be using an underlying memory buffer of char* instead of void* (perhaps combined with static arrays).