问题描述
我想知道当为DELETE运算符提供的基类指针与对象的实际内存位置不同时,它是如何计算出需要释放的内存位置的。
我想在我自己的自定义分配器/释放分配器中复制此行为。
请考虑以下层次结构:
struct A
{
unsigned a;
virtual ~A() { }
};
struct B
{
unsigned b;
virtual ~B() { }
};
struct C : public A, public B
{
unsigned c;
};
我想分配一个C类型的对象,并通过B类型的指针将其删除。据我所知,这是对操作符DELETE的有效使用,它在linux/GCC下工作:
C* c = new C;
B* b = c;
delete b;
有趣的是,由于对象在内存中的布局方式,指针‘b’和‘c’实际上指向不同的地址,并且删除操作符"知道"如何查找和释放正确的内存位置。
我知道,在给定基类指针Find out the size of a polymorphic object的情况下,通常不可能找到多态对象的大小。我怀疑通常也不可能找到对象的真实内存位置。
备注:
- 我的问题与new[]和delete[]如何工作无关。我对单一对象分配的情况感兴趣。How does delete[] "know" the size of the operand array?。
- 我也不关心析构函数是如何调用的。我对内存本身的重新分配感兴趣。How 'delete' works when I delete a pointer of base class
- 我使用-FNO-RTTI和-FNO-EXCEPTIONS进行了测试,因此G++不应该有权访问运行时类型信息。
推荐答案
这显然是特定于实现的。在实践中,实现事情的明智方法相对较少。从概念上讲,这里有几个问题:
您需要能够获取指向派生最多的对象的指针,即(概念上)包含所有其他类型的对象。
在标准C++中,可以使用
dynamic_cast
:void *derrived = dynamic_cast<void*>(some_ptr);
仅从
B*
获取C*
,例如:#include <iostream> struct A { unsigned a; virtual ~A() { } }; struct B { unsigned b; virtual ~B() { } }; struct C : public A, public B { unsigned c; }; int main() { C* c = new C; std::cout << static_cast<void*>(c) << " "; B* b = c; std::cout << static_cast<void*>(b) << " "; std::cout << dynamic_cast<void*>(b) << " "; delete b; }
在我的系统上提供了以下内容
0x912c008 0x912c010 0x912c008
一旦完成,它就成为一个标准的内存分配跟踪问题。这通常通过以下两种方式之一完成,a)记录分配内存之前的分配大小,发现大小只是指针减法,然后b)在某种数据结构中记录分配和空闲内存。有关更多详细信息,请参阅this question,这是一个很好的参考资料。
使用glibc,您可以相当明智地查询给定分配的大小:
#include <iostream> #include <stdlib.h> #include <malloc.h> int main() { char *test = (char*)malloc(50); std::cout << malloc_usable_size(test) << " "; }
该信息同样可用于释放/删除,并用于确定如何处理返回的内存块。
malloc_useable_size
的具体实现细节在libc源代码中给出,位于malloc/malloc.c:
(以下包括Colin Plumb稍加编辑的说明)
使用"边界标记"方法维护内存块,如下所示 例如,用Knuth或Stanish描述的。(见保罗·威尔逊的论文 ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps有关此类问题的调查 技术。)空闲块的大小存储在 每一块和最后一块。这使得整合零碎的块成为可能 很快就会变成更大的块。大小字段还保存位 表示区块是空闲还是正在使用。分配的区块如下所示:
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of previous chunk, if allocated | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of chunk, in bytes |M|P| mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | User data starts here... . . . . (malloc_usable_size() bytes) . . | nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Size of chunk | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
这篇关于C++delete操作符如何找到多态对象的内存位置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!