指向动态分配数组起始地址的指针不包含该数组大小的信息,需要使用另一个变量来存储以便通过指针后续处理数组。但是当我们释放动态分配的数组时,没有指定大小,而是只需使用“free ptr”或“delete [] ptr”。如何让free或delete知道数组的大小?我们能否使用相同的方案避免在另一个变量中存储数组大小?
谢谢!
指向动态分配数组起始地址的指针不包含该数组大小的信息,需要使用另一个变量来存储以便通过指针后续处理数组。但是当我们释放动态分配的数组时,没有指定大小,而是只需使用“free ptr”或“delete [] ptr”。如何让free或delete知道数组的大小?我们能否使用相同的方案避免在另一个变量中存储数组大小?
谢谢!
是的,这是真的。
delete
知道内存块的大小,因为new
会在返回给用户区域之前向内存块添加额外信息,包括它的大小和其他信息。请注意,这非常依赖于具体实现,不应该被您的代码所使用。
所以回答您的最后一个问题:不可以——它是高度依赖平台和编译器的实现细节。
例如,在K&R2中演示的样例内存分配器中,这是放置在每个分配块之前的“头”信息:
typedef long Align; /* for alignment to long boundary */
union header { /* block header */
struct {
union header *ptr; /* next block if on free list */
unsigned size; /* size of this block */
} s;
Align x; /* force alignment of blocks */
};
typedef union header Header;
size
是已分配块的大小(接下来将由free
或delete
使用)。
delete [20] arr;
就像 arr = new int[20]
一样。然而实践证明,大小信息可以轻松地由分配器存储,而且由于大多数使用它的人都会存储它,因此它被添加到了标准中。int* arr = new int[20];
delete [20] arr;
然而,令人遗憾的是,在标准中没有符合要求的方式来检索传递的大小以供自己使用 :-/
确实,数组本身不包含数组的大小信息,您需要将该信息存储以备后用。当通过delete
或free
删除数组时,传递的是指向已分配内存的指针。使用的内存管理器(系统提供的或自定义的覆盖 new 和 delete 的管理器)知道被释放的内存区域,并跟踪它。希望这能让您理解。
没错,这是为什么你应该很少直接处理它,而是使用标准容器的一部分。唯一有意义的时间是如果你决定自己实现一个容器(在这种情况下,你通常会在容器的实现中跟踪大小信息)。
new T[n]
的n
,以便在调用delete[]
时可以调用析构函数n
次。当然,它如何以及在哪里存储n
仍然与实现特定的原始块大小存储一样。 - Nick Guerrera