C++ 动态 objects。 object 大小是如何在运行时确定的?

C++ dynamic objects. How is object size determined during runtime?

有一件事我不明白。例如,我声明 class A 和 class B 是 A 的 child:

class A {
    public:
        int a;
}

class B : public A {
    public:
        int b;
}

显然,如果我创建 A 或 B 的实例,它们在内存中的大小可以由类型决定。

A instanceA; // size of this will probably be the size of int (property a)
B instanceB; // size of this will probably be twice the size of int (properties a and b)

但是如果我创建动态实例然后释放它们呢?

A * instanceAPointer = new A();
A * instanceBPointer = new B();

这些是不同 classes 的实例,但程序会将它们视为 class A 的实例。使用它们时没问题,但释放它们呢?要释放分配的内存,程序必须知道要释放的内存大小,对吗?

所以如果我写

delete instanceAPointer;
delete isntanceBPointer;

程序如何知道,从每个指针指向的地址开始,它应该释放多少内存?因为显然 objects 有不同的大小,但程序认为它们是类型 A.

谢谢

如果您通过指向基类子对象的指针删除对象并且子对象的 class 没有虚拟析构函数,则行为未定义。

另一方面,如果它确实有一个虚拟析构函数,那么虚拟分派机制会负责为正确的地址(即完整的、最派生的对象)释放正确数量的内存。

您可以通过将 dynamic_cast<void*> 应用于任何适当的基本子对象指针来自己发现最派生对象的地址。 (另见 this question。)

我假设您知道如何 delete works

至于delete如何知道如何清理继承的实例。这就是为什么你使用 virtual destructor in inheritance context, otherwise you'll have undefined behavior. Basically, the destructor, like every other virtual function is called via a vtable.

另请记住:C++ 编译器在您的析构函数

中隐式析构父 class(es)
class A {
    public:
        int a;
    virtual ~A(){}
}

class B : public A {
    public:
        int b;
    ~B() { /* The compiler will call ~A() at the very end of this scope */ }
}

这就是为什么它会起作用的原因;

A* a = new B();
delete a;

通过vtable,析构函数~B()将被delete调用。由于编译器在派生class(es)中隐式插入了基class(es)的析构函数调用,因此A的析构函数将在~B().[=24中被调用=]

To free allocated memory, the program must know the size of memory to free, right?

如果考虑 C 库 mallocfree,您会发现调用 free 时无需指定要释放的内存量,即使在那种情况下 free 提供了 void* 因此无法推断它。相反,分配库通常记录或可以充分推断所提供的内存,这样指针本身就足以进行释放。

对于 C++ 释放例程仍然如此:如果基 class 提供自己的 static void operator delete(void*, std::size_t) 基 class 析构函数是virtual,那么就会传入动态类型的大小。默认情况下,释放结束于 ::operator delete(void*),它不会被赋予任何大小:分配例程本身必须知道足够的信息才能运行。

分配例程有多种工作方式,包括:

  • 正在存储分配的大小

  • 从相同大小的块池中分配相似大小的对象,这样任何指向该池的指针都隐式地与该块大小相关