我遇到了VS调试器的问题,上面的代码是:
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”和“wntdll.pdb”的“animal.reset()”后,此代码抛出错误。
如果我点击“忽略”多次(3)次,以下是MSVC运行时库生成断言失败的表达式:
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.
但是如果我改变Dog的继承顺序,就像这样:
class Dog : public Animal, public Stupid {
public:
};
代码运行良好。
我只在visual studio 2017中出现此错误,我尝试使用Ideone,Android Studio,无论继承顺序如何,它都运行良好。
答案 0 :(得分:6)
这会中断,因为您传递给delete
的指针与从new
返回的指针不同。
向上转换基本上意味着你采用指向派生的指针并假装它是一个指向基础的指针。对于单继承,这只是起作用,因为基本部分始终是存储在派生对象中的第一件事。 但是有了多重继承,你有两个基础!
因此,当您向上转换到第二个基数时,您需要更改指针的值,以确保它指向的内容实际上是相应的基数你的一部分。您可以通过检查调试器中指针的值来验证:
Dog* d = new Dog;
Animal* a = d;
a
指针将指向d
指针后面一个字节。
如前所述,可以通过向删除调用中使用的基类类型添加虚拟析构函数来修复此问题(在示例中为Animal
)。这将导致编译器生成其他代码,以便在将指针传递给delete
之前正确地重新调整指针。
请注意,gcc实际上在这里实现了空基类优化,所以这个例子将在那里工作。两个基地将生活在相同的偏移量。当你开始将非静态数据成员添加到基类时,它将立即开始打破。