代码之家  ›  专栏  ›  技术社区  ›  VolkerK

如何删除[]“知道”操作数数组的大小?

c++
  •  209
  • VolkerK  · 技术社区  · 16 年前
    Foo* set = new Foo[100];
    // ...
    delete [] set;
    

    你不能将数组的边界传递给 delete[] . 但是这些信息存储在哪里?它是标准化的吗?

    9 回复  |  直到 8 年前
        1
  •  140
  •   Lightness Races in Orbit    14 年前

    当您在堆上分配内存时,分配器将跟踪您分配了多少内存。这通常存储在分配内存之前的“head”段中。这样,当需要释放内存时,去分配器就可以准确地知道要释放多少内存。

        2
  •  16
  •   Avt    8 年前

    编译器的一种方法是分配更多的内存,并在head元素中存储元素计数。

    示例如何完成:

    在这里

    int* i = new int[4];
    

    编译器将分配 sizeof(int)*5 字节。

    int *temp = malloc(sizeof(int)*5)
    

    将在第一个存储“4” sizeof(int) 字节

    *temp = 4;
    

    并设置 i

    i = temp + 1;
    

    所以 将指向由4个元素组成的数组,而不是5个元素。

    删除

    delete[] i;
    

    将按以下方式处理:

    int *temp = i - 1;
    int numbers_of_element = *temp; // = 4
    ... call destructor for numbers_of_element elements
    ... that are stored in temp + 1, temp + 2, ... temp + 4 if needed
    free (temp)
    
        3
  •  8
  •   Dominik Grabiec    16 年前

    信息不规范。然而,在我处理过的平台中,这些信息存储在内存中,就在第一个元素之前。因此,理论上你可以访问和检查它,但是它不值得。

    这也是为什么当您用新的[]分配内存时必须使用delete[]的原因,因为delete的数组版本知道它需要寻找适当的内存量(以及在哪里),并为对象调用适当数量的析构函数。

        4
  •  5
  •   Francisco Soto    16 年前

    基本上它在内存中的排列如下:

    [信息][您要求的备忘录…]

    其中info是编译器用来存储分配的内存量的结构,而什么不是。

    但这取决于实现。

        5
  •  3
  •   jeffm    16 年前

    这不是规范中的内容——它依赖于实现。

        6
  •  2
  •   Joel Coehoorn    16 年前

    因为要“删除”的数组应该是使用“new”运算符创建的。“new”操作应该将该信息放到堆上。否则,new的其他用法如何知道堆的结束位置?

        7
  •  2
  •   Tim Cooper    12 年前

    它在C++标准中定义为编译器专用的。这意味着编译器的魔力。它可以打破至少一个主要平台上的非平凡对齐限制。

    您可以通过认识到这一点来考虑可能的实现 delete[] 仅为返回的指针定义 new[] ,它可能与返回的指针不同 operator new[] . Wild中的一个实现是在返回的第一个int中存储数组计数 运算符new [ ] 并拥有 新[ ] 返回一个指针偏移量。(这就是为什么非平凡的对齐会中断的原因 新[ ] )

    记住 operator new[]/operator delete[] != new[]/delete[] .

    另外,这与C如何知道由 malloc .

        8
  •  0
  •   Andre    16 年前

    这是不规范的。在Microsoft的运行时中,新的运算符使用malloc(),而delete运算符使用free()。因此,在这个设置中,您的问题等价于:free()如何知道块的大小?

    后台有一些簿记工作正在进行,例如在C运行时。

        9
  •  0
  •   Chris Jefferson    9 年前

    这是一个比你起初想象的更有趣的问题。这个回复是关于一个可能的实现。

    首先,虽然在某种程度上,您的系统必须知道如何“释放”内存块,但底层malloc/free(new/delete/new[]/delete[]通常调用)并不总是准确地记住您请求的内存量,它可以被取整(例如,一旦您超过4K,它通常被取整到下一个4K大小的块)。

    因此,即使可以得到内存块的大小,也不能告诉我们新的[]ed内存中有多少值,因为它可能更小。因此,我们必须存储一个额外的整数,告诉我们有多少个值。

    除非,如果正在构造的类型没有析构函数,那么delete[]除了释放内存块之外不必做任何事情,因此不必存储任何东西!