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 库 malloc
和 free
,您会发现调用 free
时无需指定要释放的内存量,即使在那种情况下 free
提供了 void*
因此无法推断它。相反,分配库通常记录或可以充分推断所提供的内存,这样指针本身就足以进行释放。
对于 C++ 释放例程仍然如此:如果基 class 提供自己的 static void operator delete(void*, std::size_t)
和 基 class 析构函数是virtual
,那么就会传入动态类型的大小。默认情况下,释放结束于 ::operator delete(void*)
,它不会被赋予任何大小:分配例程本身必须知道足够的信息才能运行。
分配例程有多种工作方式,包括:
正在存储分配的大小
从相同大小的块池中分配相似大小的对象,这样任何指向该池的指针都隐式地与该块大小相关
有一件事我不明白。例如,我声明 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 库 malloc
和 free
,您会发现调用 free
时无需指定要释放的内存量,即使在那种情况下 free
提供了 void*
因此无法推断它。相反,分配库通常记录或可以充分推断所提供的内存,这样指针本身就足以进行释放。
对于 C++ 释放例程仍然如此:如果基 class 提供自己的 static void operator delete(void*, std::size_t)
和 基 class 析构函数是virtual
,那么就会传入动态类型的大小。默认情况下,释放结束于 ::operator delete(void*)
,它不会被赋予任何大小:分配例程本身必须知道足够的信息才能运行。
分配例程有多种工作方式,包括:
正在存储分配的大小
从相同大小的块池中分配相似大小的对象,这样任何指向该池的指针都隐式地与该块大小相关