包含分配指针的结构向量无法析构
Vector of structs containing allocation pointers is failing to destruct
在我的项目中,我使用 class 进行分页内存分配。
class 使用一个结构来存储它的所有分配:
enum PageStatus : uint_fast8_t { //!< possible use stati of an allocated page
PAGE_STATUS_INVALID = 0b00,
PAGE_STATUS_FREE = 0b01, //!< the page is free
PAGE_STATUS_USED = 0b10, //!< the page is (partially) used
};
struct PhysicalPage { //!< represents a page that has been allocated
char* pData; //!< pointer to the allocation
PageStatus status; //!< status of the allocation
};
这些PhysicalPage
存储在向量std::vector<PhysicalPage> physicalAllocations {};
中。
在运行时页面被添加到向量中,有些可能会被删除。在删除过程中,弹出最后一个元素并使用 delete page.pData
返回内存。但是,当分配器 class 到达生命终点并从堆栈中释放时,就会出现问题。当调用 pyhsicalAllocations
的向量析构函数时,它不仅会尝试破坏元素本身,还会尝试破坏保留的内存(向量在更改大小时将其保留为缓冲区)。这会导致删除无效的内存指针,从而停止程序执行:
double free or corruption (!prev)
Signal: SIGABRT (Aborted)
可能还值得一提的是,分配是在大于页面的块中完成的,这意味着每个 x 指针中只有一个是实际有效的分配。所有其他指针只是实际内存位置的偏移量。
为了防止错误发生,我尝试了:
手动删除(由于分块分配,这有点过于复杂)
for (size_t i = physicalAllocations.size(); 0 < i; i -= 1 << allocationChunkSize) {
delete physicalAllocations[i - (1 << allocationChunkSize)].pData;
for (size_t a = 0; a < 1 << allocationChunkSize; a++)
physicalAllocations.pop_back();
}
清除向量
physicalAllocations.clear();
交换清晰的矢量
std::vector<PhysicalPage>(0).swap(physicalAllocations);
其中 none 有效。
我想承认我已经在这个问题上工作了很长时间,非常感谢你的帮助。谢谢!
std::shared_ptr<char[]> pData
及其 aliasing constructor (8) 可能会有所帮助。 (这甚至可能允许摆脱 PageStatus)。
它看起来像:
constexpr std::size_t page_size = 6;
struct PhysicalPage {
std::shared_ptr<char[]> pData;
};
int main()
{
std::vector<PhysicalPage> pages;
{
std::shared_ptr<char[]> big_alloc = std::unique_ptr<char[]>(new char[42]{"hello world. 4 8 15 16 23 42"});
for (std::size_t i = 0; i != 42 / page_size; ++i) {
pages.push_back(PhysicalPage{std::shared_ptr<char[]>{big_alloc, big_alloc.get() + i * page_size}});
}
}
pages.erase(pages.begin());
pages.erase(pages.begin() + 2);
for (auto& p : pages) {
std::cout << std::string_view(p.pData.get(), page_size) << std::endl;
}
}
在我的项目中,我使用 class 进行分页内存分配。 class 使用一个结构来存储它的所有分配:
enum PageStatus : uint_fast8_t { //!< possible use stati of an allocated page
PAGE_STATUS_INVALID = 0b00,
PAGE_STATUS_FREE = 0b01, //!< the page is free
PAGE_STATUS_USED = 0b10, //!< the page is (partially) used
};
struct PhysicalPage { //!< represents a page that has been allocated
char* pData; //!< pointer to the allocation
PageStatus status; //!< status of the allocation
};
这些PhysicalPage
存储在向量std::vector<PhysicalPage> physicalAllocations {};
中。
在运行时页面被添加到向量中,有些可能会被删除。在删除过程中,弹出最后一个元素并使用 delete page.pData
返回内存。但是,当分配器 class 到达生命终点并从堆栈中释放时,就会出现问题。当调用 pyhsicalAllocations
的向量析构函数时,它不仅会尝试破坏元素本身,还会尝试破坏保留的内存(向量在更改大小时将其保留为缓冲区)。这会导致删除无效的内存指针,从而停止程序执行:
double free or corruption (!prev)
Signal: SIGABRT (Aborted)
可能还值得一提的是,分配是在大于页面的块中完成的,这意味着每个 x 指针中只有一个是实际有效的分配。所有其他指针只是实际内存位置的偏移量。
为了防止错误发生,我尝试了:
手动删除(由于分块分配,这有点过于复杂)
for (size_t i = physicalAllocations.size(); 0 < i; i -= 1 << allocationChunkSize) {
delete physicalAllocations[i - (1 << allocationChunkSize)].pData;
for (size_t a = 0; a < 1 << allocationChunkSize; a++)
physicalAllocations.pop_back();
}
清除向量
physicalAllocations.clear();
交换清晰的矢量
std::vector<PhysicalPage>(0).swap(physicalAllocations);
其中 none 有效。
我想承认我已经在这个问题上工作了很长时间,非常感谢你的帮助。谢谢!
std::shared_ptr<char[]> pData
及其 aliasing constructor (8) 可能会有所帮助。 (这甚至可能允许摆脱 PageStatus)。
它看起来像:
constexpr std::size_t page_size = 6;
struct PhysicalPage {
std::shared_ptr<char[]> pData;
};
int main()
{
std::vector<PhysicalPage> pages;
{
std::shared_ptr<char[]> big_alloc = std::unique_ptr<char[]>(new char[42]{"hello world. 4 8 15 16 23 42"});
for (std::size_t i = 0; i != 42 / page_size; ++i) {
pages.push_back(PhysicalPage{std::shared_ptr<char[]>{big_alloc, big_alloc.get() + i * page_size}});
}
}
pages.erase(pages.begin());
pages.erase(pages.begin() + 2);
for (auto& p : pages) {
std::cout << std::string_view(p.pData.get(), page_size) << std::endl;
}
}