包含分配指针的结构向量无法析构

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;
    }
}

Demo