【问题标题】:How does the delete in C++ know how many memory locations to deleteC++中的delete怎么知道要删除多少内存位置
【发布时间】:2011-01-20 15:13:53
【问题描述】:

删除操作符是如何工作的?它比 free() 更好吗?另外如果你做ptr=new char[10],然后用delete ptr删除,指针怎么知道要删除多少个位置。

【问题讨论】:

  • 我认为您的意思是 delete 运算符。
  • 你需要删除 [] ptr 否则你会遇到麻烦。
  • 冒昧澄清一下您的标题,希望您不要介意。此外,如果您想知道特定的编译器和平台,最好包含它。不同的编译器可能有不同的方法来解决您所询问的问题。
  • g++ 在 fedora 上,这个标题也更好用

标签: c++ memory-management


【解决方案1】:

只有delete 运算符,free 仅作为函数存在。在 C++ 下,鼓励您使用 new/delete 而不是 malloc()/free()


删除操作符有一个内在的“魔力”。当使用new[] 创建数组时,数组的大小存储在内存块的元数据中。 delete[] 使用该信息。

当然,所有这些都取决于编译器、操作系统、优化器和实现。

【讨论】:

  • 我建议将new 改为new[]delete 改为delete[]
  • 如果您错误地使用delete ptr 而不是delete [] ptr,“魔法”可能会或可能不会正常工作,同样非常依赖于实现。
  • 我永远无法理解为什么 C++ 会在内部传递数组大小,但不允许您访问它们,迫使您自己传递数组大小。
  • @BlueRaja:如果您创建一个 n 字节长的数组,C++ 没有义务为该数组准确分配 n 字节——它可以分配更多,例如以确保对齐。
  • @BlueRaja:因为 C++ 不是需要知道数组大小的。具体实现可能知道数组的大小(以bytes 为单位),但不知道最大数组index(因为它不关心item 的大小)。另一方面,如果您还需要知道大小,也许您需要std::vector 而不是数组?
【解决方案2】:

如果你做的是非数组类型:

T t = new T;
// ...
delete t;

它会知道要删除多少,因为它知道 T 有多大。如果你做一个数组:

T t* = new T[10];
// ...
delete [] t;

它会在分配中放置一些额外的信息,告诉它要删除多少。注意,我们使用delete [] t 和额外的[] 来告诉它它是一个数组。如果你不这样做,它会认为它只是一个T,并且只会释放那么多内存。

如果您使用new,请始终使用delete;如果您使用malloc,请始终使用freenew 首先做了两件事,分配内存,然后构造对象。同样delete 调用析构函数然后释放内存。 malloc\free只处理内存分配和释放。

【讨论】:

    【解决方案3】:
    1. 在 C++ 中,使用 new 调用构造函数,但在使用 malloc 时不调用。同样,使用 delete 时会调用析构函数,但使用 free 时不会调用。

    2. 如果您使用 MyClass* x = new MyClass[25] 新建了一个数组,那么您需要调用 delete[] x,以便系统知道它正在删除(和破坏)一组对象而不是单个对象。

    【讨论】:

      【解决方案4】:

      该实现为您计算出要销毁的元素数量(使用 delete[] 时)。例如:

      • new char[10] 可以分配几个额外的字节,将元素的数量放在开头,然后返回指向第一个元素的指针。然后 delete[] 可以在指针后面查看存储的计数
      • 存储等效于 std::map 和 new T[n] 将使用返回的指针创建一个键,并使用计数创建一个值。 delete[] 会在这个地图中查找指针
      • 完全不同的东西。它是如何完成的对你来说并不重要,只是它完成了(正如其他答案所指出的那样,将 delete[] 与 new[] 一起使用!!)

      【讨论】:

        【解决方案5】:

        这不是好坏的问题。两者都是具有相同目标的操作,分配和释放内存,但通常在 C 与 C++ 的不同上下文中使用。此外,这两组操作之间还有一些重要的区别:

        • new / delete 是 C++ 关键字,在 C 语言中不可用
        • new / delete 是类型安全的,而 malloc() / free() 不是。这意味着malloc()free() 返回的指针是void 需要转换为正确类型的指针。
        • new / delete 隐式支持使用 new[]delete[] 语法使用编译器提供的元数据进行数组分配和删除,malloc() / free() 不支持此语法
        • new/delete应用于类类型T将分别调用Tmalloc()/free()的构造函数和析构函数,不要调用T的构造函数和析构函数
        • malloc()会在内存耗尽的情况下返回NULLnew会抛出异常

        请注意,为防止内存损坏,使用new 分配的内存应使用delete 释放。使用malloc() 分配的内存也是如此,应该使用free() 释放。

        【讨论】:

          【解决方案6】:

          具体回答您的问题,delete 运算符调用析构函数,而 free 没有;因此,您不想将 malloc/free 与 new/delete 混合使用。

          当编译器的库从堆中获取内存时,它会比您要求的多一点,其中包括用于其内部管理的空间、一些元数据以及(如果需要)填充。

          假设你 malloc 128 字节,或者新建一个由 8 个 16 字节大小的对象组成的数组。编译器实际上可能会抓取 256 个字节,在开始时包含一个小的堆管理块,记录它给了您 128 但抓取了 256,并在其标头之后的某个位置返回到该 256 块的偏移量。您可以保证从该指针中可以使用 128 个字节,但如果超出此范围,您可能会遇到麻烦。

          底层的 free 和 delete 操作符会获取你收到的指针,备份一个已知的偏移量,读取它的头块,并知道将 256 字节释放回堆。

          【讨论】:

            【解决方案7】:

            如果您使用运算符的 new[] 形式分配内存,则添加到@Vlad 的答案,例如:

            char *c = new char[10];
            

            那你就得使用对应的删除形式了:

            delete[] c;
            

            您必须明确告诉编译器在释放期间使用元数据。

            [编辑]

            为什么不能使用 char c[]

            因为编译器需要知道它需要在编译时为变量 c 留出的大小。然而,使用 new[] 形式告诉它推迟分配直到运行时。因此,编译器错误。

            【讨论】:

            • char c[] = new char[10]; 无法编译,您应该将c[] 更改为*c
            • 该语句不合法,不能更改字符数组的指针。我想你的意思是说 char *c
            • 即使你做了 delete c,我敢打赌它会起作用。不要问我为什么:)>
            猜你喜欢
            • 1970-01-01
            • 2023-03-20
            • 1970-01-01
            • 2010-11-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-16
            相关资源
            最近更新 更多