【发布时间】:2020-01-24 05:59:38
【问题描述】:
经过多次挠头后,我想我已经发现了问题所在。代码:
struct Block {
union {
void* address;
Block* next;
};
size_t size;
};
void* FragmentedMemoryManager::allocate(size_t size) {
if(allocationCount == maxAllocations) return nullptr;
Block** prev = &head;
Block* curr = head;
for(;
curr != nullptr;
prev = &curr,
curr = curr->next
)
{
if(curr->size < size) {
continue;
}
Block allocBlock = Block{
address: curr,
size: size
};
allocations[allocationCount++] = allocBlock;
size_t newSize = curr->size - size;
//pretty sure this will wrap if it goes 'negative'
assert(newSize < curr->size);
//curr was completely allocated
if(newSize == 0) {
*prev = curr->next;
} else {
void* newAddress = toPtr(toUPtr(curr) + size);
Block* newBlock = reinterpret_cast<Block*>(newAddress);
newBlock->next = curr->next;
newBlock->size = newSize;
if(*prev == head) {
*prev = newBlock;
} else {
//I know that this fails because prev is a double ref,
//updating curr in the loop unintentionally updates prev
//see line 36
(*prev)->next = newBlock;
}
}
std::sort(
allocations, allocations + allocationCount,
[](Block a, Block b)
{
return a.address < b.address;
});
memset(allocBlock.address, 0, size);
return allocBlock.address;
}
return nullptr;
}
我确信这个想法是正确的,因为我需要做 (*prev)->next = newBlock,我不知道如何在更新 curr 的同时保留 prev 的预期引用。我该怎么做?
缩进的结果很不稳定。因为这里发生的事情不仅仅是添加到列表中。 prev 有可能完全跳过 curr,本质上是“删除”curr。我将节点直接写入未分配的内存区域。
【问题讨论】:
-
我希望您理解
prev = &curr将总是 分配相同的地址(地址curr,而不是地址由curr持有 到prev,无论是否在循环中,无论curr持有的指针值是多少。这应该是一个单链表,你要插入一个新节点(中间,头部,尾部,没有区别)?老实说,我认为你在这个根本中不需要prev。 -
在学术上我明白这一点。这对我来说是一个相当新的领域,所以我有点磕磕绊绊。是的,curr 的类型是 Block*。存储此信息的地址是不变的。我可能在这里不需要双重参考,只是很难想出一些有效的东西。
-
将 prev 更改为一个指针并明智地使用 ifs 让这件事起作用。要关闭这个,我不需要双重参考......