如果内存块被手动覆盖,如何删除结构数组

How to delete the array of structures if the memory block was manually overwritten

我知道下面提供的示例是一个相当糟糕的模式,但出于好奇我想问这个问题。

在这种情况下:

int main (int argc, char **argv) {
    struct MyStruct {
        virtual ~MyStruct() = default;
        int dummyField;
    };
    int numpack = 1000;
    int memoryBlockSize = numpack*sizeof(MyStruct);
    char* buf = new char[memoryBlockSize];
    memset(buf, 0, memoryBlockSize);
    {
        MyStruct packets[numpack];
        memcpy(&packets, buf, memoryBlockSize);
    }  // segmentation fault on scope exit
    MyStruct* packets = new MyStruct[numpack];
    memcpy(packets, buf, memoryBlockSize);
    delete[] packets;  // segmentation fault on delete attempt
    delete[] buf;

    return 0;
}

分段错误是预期的,因为在 packets 销毁时不可能在 MyStruct's 虚拟 table 中找到析构函数(内存被零覆盖)。在这种情况下,是否可以优雅地删除packets指向的内存块?

也许可以为删除函数提供(指针+块大小)?

或者我可以尝试通过从另一个以相同方式分配的内存块复制内存来修复 packets 指向的块(但是虚拟 table 中的指针将指向一个内存中的不同位置):

MyStruct* anotherPackets = new MyStruct[numpack];
memcpy(packets, anotherPackets, memoryBlockSize);

这取决于MyStruct。如果它有一个非平凡的析构函数,因为例如它包含一个非空的 std::string 对象,那么你已经丢失了,因为当你擦除该对象时,你将创建一个字符串字符的内存泄漏。取决于子对象,情况甚至可能更糟。

但是只要packets超出作用域时析构函数能成功调用,就可以简单地用一个placement new来构造(new)数组内的对象:

{
    MyStruct packets[numpack];
    memcpy(&packets, buf, memoryBlockSize);
    for (int i=0; i<numpack; i++) {
        new(packets+i) MyStruct();  // re-creates an object
    }
}   // the new objects are being destructed here

但是由于尚未在初始对象上调用析构函数,因此任何事情都可能发生(这就是未定义行为的意思...)。所以请永远不要在实际代码中这样做