带有和没有虚拟驱动器的内存管理

Memory management with and without the virtual destructor

本文关键字:内存 管理 驱动器 虚拟      更新时间:2023-10-16

为什么虚拟破坏者在内存管理中使这些不同?

我有一个课程:

class A
{
public:
    A() : m_x(0) { }
    ~A() {}
public:
    static ptrdiff_t member_offset(const A &a)
    {
        const char *p = reinterpret_cast<const char*>(&a);
        const char *q = reinterpret_cast<const char*>(&a.m_x);
        std::cout << "n&a   =" << &a << "n&a.mx=" << &a.m_x << "np=" << (int)p << " q=" << (int)q << 'n';
        return q - p;
    }
private:
    int m_x;
};

,如果我打电话给A a; member_offset(a);,我将被打印:

&a   =002EFD28
&a.mx=002EFD28
p=3079464 q=3079464

如果我制作了destructor virtual,我会得到其他地址:

&a   =002EFD28
&a.mx=002EFD2C
p=3079464 q=3079468

为什么?虚拟破坏者对内存管理有什么影响?

一个虚拟方法表指针添加到类的每个实例中 - 通常在对象的开头。它不一定是驱动器,任何第一个virtual方法都会确定虚拟方法表的生成。

没有虚拟函数(并满足其他各种约束),类具有标准布局,并且保证其第一个数据成员的地址与对象本身。

使用一个或多个虚拟函数,它是多态,并且不再具有标准布局,并且没有这样的保证。通常,通过添加隐藏的指针(有时称为虚拟指针或 vptr )来实现多态性,指向特定于类的虚拟函数表(有时已知)如 vtable )和其他动态类型信息。在这种情况下,看起来这个指针是在声明的成员面前的,导致您观察到的地址差异。