覆盖new和成员访问运算符以使用自定义堆

时间:2018-02-24 23:53:00

标签: c++

我一直在研究一个小项目,以了解动态内存分配的工作原理。我有一个全局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,我希望它们存储在堆栈中

我尝试在网上查找信息,但我似乎无法找到任何线索。我甚至不确定这是可能的。任何帮助将不胜感激

2 个答案:

答案 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);
}

将这些调整直接放入AllocDeAlloc可能是一个好主意,以防止可能的错误破坏您的堆。这正是许多mallocfree实现所做的事情,因此它是分配函数的预期行为,并且它阻止用户需要知道堆的内部结构使用它。

答案 1 :(得分:0)

首先,

SimpleStruct s = new SimpleStruct(5);

应该是:

SimpleStruct* s = new SimpleStruct(5);

这是你问题的根源吗?

您不需要重载->。当你new一个类的实例时,在堆上分配所需的内存量,如果成功,你的类构造函数被称为 over 这个内存(this是指向这个内存的指针记忆)。您的变量位于此内存块中,编译器可以从this计算其位置。

实现自定义内存分配时,唯一的区别是内存不是从全局堆中分配的,而是指向某个内存的指针。其余的是相同的:你有一个指向你的类实例的指针,当你编写this->xs->x时,编译器知道如何访问这个成员,因为它知道它从实例表示开始的“转移”记忆。