我一直在研究一个小项目,以了解动态内存分配的工作原理。我有一个全局char缓冲区,我用作我的堆。阅读these lecture notes后,我编写了Alloc,DeAlloc,MergeBlocks和SplitBlocks函数进行内存管理。 Alloc和DeAlloc的功能类似于malloc和free,但是因为它们写入了我的堆数组。现在,我让他们工作,我想知道如何重载一个简单的类来使用我的内存管理。
// Memory Block structure
// -------------------------------
// | size | active | 2 bytes
// -------------------------------
// | | n bytes
// | payload |
// | |
// -------------------------------
// | padding | m bytes (n + m + 4 is a multiple of 8)
// -------------------------------
// | size | active | 2 bytes
// -------------------------------
unsigned char heap[2064]; // fake heap
// -----------------------------------------------------------------------
// Omitting a bunch of memory management functions that manage the heap
// -----------------------------------------------------------------------
struct SimpleStruct
{
unsigned short x;
SimpleStruct(unsigned short x)
{
this->x = x;
}
// Need to override -> operator but not sure what to do
void* operator new(size_t size)
{
return (void*)Alloc(size);
}
};
int main()
{
SimpleStruct* s = new SimpleStruct(5);
s->x = 3;
}
我觉得我需要做一些事情:
首先,我需要将成员变量值实际存储在自定义堆
上其次我需要这样做,以便 - >()运算符在堆中的适当位置查找以查找成员变量。我可以在构造函数中执行此操作,但如果未使用new,我希望它们存储在堆栈中
我尝试在网上查找信息,但我似乎无法找到任何线索。我甚至不确定这是可能的。任何帮助将不胜感激
答案 0 :(得分:1)
您的对象将在operator new
返回的地址处构建。如果Alloc
返回的地址指向块的元数据,则operator new
需要将指针调整为该对象不会覆盖元数据:
void* operator new(size_t size)
{
char* block = (char*)Alloc(size);
return (void*)(block + 2);
}
然后你需要一个匹配的operator delete
,它可以找到给定指向有效载荷的指针的元数据:
void operator delete(void* ptr)
{
char* block = (char*)ptr - 2;
DeAlloc(block);
}
将这些调整直接放入Alloc
和DeAlloc
可能是一个好主意,以防止可能的错误破坏您的堆。这正是许多malloc
和free
实现所做的事情,因此它是分配函数的预期行为,并且它阻止用户需要知道堆的内部结构使用它。
答案 1 :(得分:0)
首先,
SimpleStruct s = new SimpleStruct(5);
应该是:
SimpleStruct* s = new SimpleStruct(5);
这是你问题的根源吗?
您不需要重载->
。当你new
一个类的实例时,在堆上分配所需的内存量,如果成功,你的类构造函数被称为 over 这个内存(this
是指向这个内存的指针记忆)。您的变量位于此内存块中,编译器可以从this
计算其位置。
实现自定义内存分配时,唯一的区别是内存不是从全局堆中分配的,而是指向某个内存的指针。其余的是相同的:你有一个指向你的类实例的指针,当你编写this->x
或s->x
时,编译器知道如何访问这个成员,因为它知道它从实例表示开始的“转移”记忆。