C 多重继承和向上的智能指针破坏会导致VS 2017中的堆腐败

C++ multiple inheritance and upcasted smart pointer destruction causes heap corruption in VS 2017

本文关键字:2017 VS 多重继承 智能 指针      更新时间:2023-10-16

我遇到了vs debugger的问题,上面的代码:

class Animal {
public:

};

class Stupid {
public:
};

class Dog : public Stupid, public Animal {
public:

};
int main() {
    std::unique_ptr<Animal> animal = std::unique_ptr<Dog>(new Dog());
    animal.reset();
    return 0;
}

此代码在执行涉及" ntdl.dll"answers" wntdll.pdb"的" andial.reset(("之后会引发错误。

这是MSVC运行时库生成断言失败的表达式,如果我点击了"忽略"多(3(次:

1- _CrtIsValidHeapPointer(block)
2- is_block_type_valid(header->_block_use)
3- HEAP CORRUPTION DETECTED: before Free block (#-50331640) at 0x03737E21. CRT detected that the application wrote to memory before start of heap buffer.

但是,如果我更改狗的继承顺序,则是这样:

class Dog : public Animal, public Stupid {
public:

};

代码运行正常。

我只有在Visual Studio 2017中才有此错误,我尝试使用Ideone,Android Studio,无论继承顺序如何。

这断开了,因为您将您传递给delete的指针与从new返回的指针不同。

上铸造基本上意味着您将指针衍生为衍生,并假装它是指指底座。对于单个继承,这只是可行的,因为基础部分始终是存储在派生对象中的第一件事。但是有了多个继承,您有两个基础!

因此,当您对第二个底座进行铸造时,您需要更改指针的值,以确保指向它的指向实际上将是对象的各自的基数部分。您可以通过检查调试器中的指针值来验证这一点:

Dog* d = new Dog;
Animal* a = d;

a指针将指向d指针后面的一个字节。

如前所述,可以通过在删除呼叫中使用的基类类型中添加虚拟破坏者(示例中的Animal(来解决此问题。这将导致编译器生成其他代码以正确调整指针,然后再将其传递给delete

请注意,GCC实际上在此处实现了空基类优化,因此此示例将在此工作。两个基地都将生活在相同的偏移量中。它将开始在此处分解,并且一旦您开始在基本类中添加非静态数据成员。