我一直在做一些关于游戏引擎开发的研究,最后我开始尝试编写一个Memorymanager。我从Eberly的游戏引擎设计书中得到了这个想法。在构造函数中,我分配一个内存块并为其添加页眉和页脚,它们都具有size属性并使用。但是现在我得到了一个Access Writing Voilation。我已经听说过一些指针是const并且只能读取,但我不知道如何解决这个问题。
这是MemoryManager.h文件:
// MemoryManager.h - Header file //
#ifndef H_MemoryManager
#define H_MemoryManager
#include "IMemoryManager.h"
class HeaderBlock
{
public:
bool Used;
unsigned int Size;
HeaderBlock* Prev;
HeaderBlock* Next;
};
class FooterBlock
{
public:
bool Used;
unsigned int Size;
};
class MemoryManager : public IMemoryManager
{
private:
int m_MemoryBudget;
char* m_FullMemory;
HeaderBlock* m_FreeBlock;
int m_hsize; // Size of the header
int m_fsize; // Size of the footer
int m_hfsize; // Size of the HeaderandFooter
public:
// Constructor and Destructor
MemoryManager(int Budget);
virtual ~MemoryManager();
// Functions
virtual char* Allocate(unsigned int RequestSize);
virtual char* Deallocate(char* pDeallocate);
HeaderBlock* SearchByPolicy(unsigned int RequestSize);
};
#endif
这是构造函数实现:
MemoryManager::MemoryManager(int Budget)
{
m_MemoryBudget = Budget;
m_FullMemory = (char*)malloc(m_MemoryBudget);
m_hsize = sizeof(HeaderBlock);
m_fsize = sizeof(FooterBlock);
m_hfsize = m_hsize + m_fsize;
HeaderBlock* header = (HeaderBlock*)m_FullMemory;
header->Used = false;
header->Size = m_MemoryBudget;
FooterBlock* footer = (FooterBlock*)(m_FullMemory + m_MemoryBudget - m_fsize);
footer->Used = false;
footer->Size = m_MemoryBudget;
header->Prev = header;
header->Next = header;
m_FreeBlock = (HeaderBlock*)m_FullMemory;
}
这是分配方法,我在错误中得到错误
usedHeader->Used = true;
usedFooter->Used = true;
freeHeader->Used = false;
freeFooter->Used = false; // HERE I GET THE EXCEPTION
char* MemoryManager::Allocate(unsigned int RequestSize)
{
HeaderBlock* header = SearchByPolicy(RequestSize);
if(header == NULL)
{
return NULL;
}
unsigned int Size = header->Size;
FooterBlock* footer = (FooterBlock*)((header + Size - m_fsize));
// 1.The size to be allocated fits EXACTLY in the Block pointed by header.
if(Size == RequestSize + m_hfsize)
{
char* allocated = (char*)header + m_hsize;
header->Used = true;
footer->Used = true;
if(header->Next == header)
{
// This is the only block on the free list
m_FreeBlock = 0;
}
else
{
m_FreeBlock->Prev->Next = m_FreeBlock->Next;
m_FreeBlock->Next->Prev = m_FreeBlock->Prev;
m_FreeBlock = m_FreeBlock->Next;
}
return allocated;
}
// 2. The block has more storage than is needed for the allocation request.
if(Size >= RequestSize + 2*m_hfsize)
{
char* allocated = (char*)(header + m_hsize);
// Split the block in a "Used"-Block and a "Free"-Block
HeaderBlock* usedHeader = header;
FooterBlock* usedFooter = (FooterBlock*)(header + m_hsize + RequestSize);
HeaderBlock* freeHeader = (HeaderBlock*)(usedFooter + m_fsize);
FooterBlock* freeFooter = footer;
usedHeader->Used = true;
usedFooter->Used = true;
freeHeader->Used = false;
freeFooter->Used = false;
unsigned int usedSize = RequestSize + m_hfsize;
freeHeader->Size = header->Size - usedSize;
usedHeader->Size = usedSize;
freeHeader->Prev = header->Prev;
freeHeader->Next = header->Next;
m_FreeBlock = freeHeader;
return allocated;
}
// 3. The block has more storage then the Request, but to less to divide into two blocks.
char* allocated = (char*)header + m_hsize;
header->Used = true;
footer->Used = true;
//Detach from the free list;
if(header->Next == header)
{
// This is the only block on the free list
m_FreeBlock = 0;
}
else
{
m_FreeBlock->Prev->Next = m_FreeBlock->Next;
m_FreeBlock->Next->Prev = m_FreeBlock->Prev;
m_FreeBlock = m_FreeBlock->Next;
}
return allocated;
}
我已经检查过SearchByPolicy函数是否返回一个有效指针,如果它能找到比请求更大的内存块,它确实会返回一个有效指针。
我希望你能帮助我!
答案 0 :(得分:3)
你的问题是指针算法之一:
FooterBlock* footer = (FooterBlock*)((header + Size - m_fsize));
装置
FooterBlock* footer = (FooterBlock*)((uint_ptr)header + (sizeof(HeaderBlock) * Size) - (sizeof(HeaderBlock) * m_fsize));
你最有可能想要的:
uint_ptr ofs = (uint_ptr)header;
FooterBlock* footer = (FooterBlock*)((ofs + Size - m_fsize));
您可以在uint_ptr
或stdint.h
中的UINT_PTR
找到windows.h
<强>更新强>
根据评论中的问题
IMemoryManager* memorymanager = new MemoryManager(1000000);
Logger* logger = (Logger*)memorymanager->Allocate(sizeof(Logger));
logger->WriteToBuffer(log, "HOI");
这会失败,因为Logger
的构造函数不会被调用,有几种方法可以解决这个问题:
(不幸的是,列出了断码格式,所以我必须在这里插入...)
IMemoryManager* memorymanager = new MemoryManager(1000000);
Logger* logger = new (memorymanager->Allocate(sizeof(Logger))) ();
logger->WriteToBuffer(log, "HOI");
::new
和::delete
运算符(非常糟糕)new
和delete
:这要求内存管理器在那时可用(或作为参数传递):
class PoolObject
{
void* operator new (std::size_t n)
{
return memorymanager->Allocate(n);
}
void operator delete (void* p)
{
memorymanager->Free(p);
}
}
class Logger : PoolObject
{
}
Logger* logger = new Logger();