动态分配数组的大小

16

指向动态分配数组起始地址的指针不包含该数组大小的信息,需要使用另一个变量来存储以便通过指针后续处理数组。但是当我们释放动态分配的数组时,没有指定大小,而是只需使用“free ptr”或“delete [] ptr”。如何让free或delete知道数组的大小?我们能否使用相同的方案避免在另一个变量中存储数组大小?

谢谢!

4个回答

18

是的,这是真的。

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是已分配块的大小(接下来将由freedelete使用)。


1
请注意,从分配器实现的角度来看,分配的块的大小可能比用户请求的大小要大。 - Nick Guerrera
此外,除了原始底层块的大小之外,如果类型T有一个析构函数,那么系统必须在某个地方存储传递给new T[n]n,以便在调用delete[]时可以调用析构函数n次。当然,它如何以及在哪里存储n仍然与实现特定的原始块大小存储一样。 - Nick Guerrera

7
有趣的是,历史上它是 delete [20] arr; 就像 arr = new int[20]一样。然而实践证明,大小信息可以轻松地由分配器存储,而且由于大多数使用它的人都会存储它,因此它被添加到了标准中。
更有趣的是,鲜为人知的是,这种“扩展删除语法”实际上受到了一些C++编译器的支持(尽管在面对C++98标准时是不正确的),尽管没有一个编译器要求使用它。
int* arr = new int[20];
delete [20] arr;

然而,令人遗憾的是,在标准中没有符合要求的方式来检索传递的大小以供自己使用 :-/


它可能是“受支持的” - 但它不是C++标准的一部分。 - anon
是的,我扩展了我的回答。我想知道是否有任何标准文档可用来记录该“功能”。 - Kornel Kisielewicz

3

确实,数组本身不包含数组的大小信息,您需要将该信息存储以备后用。当通过deletefree删除数组时,传递的是指向已分配内存的指针。使用的内存管理器(系统提供的或自定义的覆盖 new 和 delete 的管理器)知道被释放的内存区域,并跟踪它。希望这能让您理解。


2

没错,这是为什么你应该很少直接处理它,而是使用标准容器的一部分。唯一有意义的时间是如果你决定自己实现一个容器(在这种情况下,你通常会在容器的实现中跟踪大小信息)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接