【问题标题】:When to delete[] a pointer c++?何时删除 [] 指针 c++?
【发布时间】:2026-02-12 13:55:02
【问题描述】:

我一直在玩 c++ 一段时间,从 java 开始,对我来说最令人困惑的方面之一是内存管理。例如,假设我有一个方法,在该方法中我声明了一个指向对象的指针,我想使用 get 方法将该指针设置为另一个对象的属性:

SubObject *mySubObject = anotherObject.getSubObject();

我的问题是,当方法结束时这个指针会发生什么?我应该在它结束之前使用以下内容吗?

delete mySubObject;

如果我不删除它会怎样?它会一直持续到整个程序结束吗?

我已经尝试在谷歌上搜索 C++ 的基本内存管理教程,但我通常会发现更高级的东西,这超出了我的想象,任何推荐都会被欣赏。

【问题讨论】:

  • 不了解anotherObject.getSubObject()很难给你一个好的答案
  • 完成后删除
  • 到底是什么问题?何时使用 delete[] 或何时使用 delete? @hexa 和 @Avada Kedavra 的回答解决了这些问题。
  • 查看 this question 以获取有关 C++ 中对象删除的帮助
  • 因为答案取决于 anotherObject.getSubObject() 和您的函数的作用。不要相信任何说删除或不删除而不要求进一步澄清的人。

标签: c++ memory pointers


【解决方案1】:

跟踪内存管理可能是一种负担,最好的建议是尽可能避免它,并通过避免使用原始指针来明确它。如果您只需要临时访问保存在其他地方的变量(在您的示例中,它是不同对象的成员,因此在那里管理)您不应该delete 它,如果您只持有它会更好reference 而不是指针,因为引用明确表明您没有管理该资源。

【讨论】:

  • 你能详细说明一下这个reference吗?还是直接给我链接?我是一名 C 程序员,开始向 C++ 迁移,这似乎是记录代码的好方法
  • 基本上你需要阅读给定函数的文档。不幸的是,很多 C++ 库的文档都没有提到你是否拥有返回的指针。
  • @hexa:你应该得到一些好的入门书籍或教程。引用是 C++ 的一项功能,用于为现有对象创建别名。在底层,它们可以实现为自动取消引用的指针,但重要的是它们保证不为空,并且它们不持有资源(内存)。作为一个简单的激励示例:int main() { int i = 0; int & r = i; r = 5; std::cout << i; } 将打印 5。变量 ri 的别名(初始化变量)
  • 哦,我明白了。我已经在无数次调用中看到了我一直在 Qt 中使用的方法,并且一直认为它们只是指针。我真的需要认真阅读一本书,而不是一路上以不太理想的方式捡东西:P 谢谢
【解决方案2】:

如果getSubObject() 方法只是返回一个指向先前分配的mySubObject 的指针,则不应删除它,因为这应该是首先分配它的类的责任。此外,该指针甚至可能没有通过 new 分配并位于堆栈中,因此删除它可能会导致更大的问题。

根据经验,delete 你有什么new'd。当然,这在很大程度上取决于编程的布局。

【讨论】:

    【解决方案3】:

    要回答帖子标题中的问题,当且仅当您使用new[] 分配内存时,您才应该使用delete[]。当且仅当您使用new 分配内存时,您才应该使用delete

    int *array = new int[10];
    int *ptr = new int;
    ...
    delete[] array;
    delete ptr;
    

    要回复您的帖子,您应该问自己代码何时分配内存。实际上,您应该将内存视为一种资源,就像文件句柄或网络连接一样。每当您在 C++ 或 Java 中打开文件时,完成后,您应该关闭这些文件。同样,每当您在 C++ 中分配内存时,都应该释放它。棘手的问题是何时应该释放内存。方法也是如此

    anotherObject.getSubObject();
    

    返回一个指向新分配对象的指针?释放上述方法返回的指针所指向的内存是谁的工作?

    如果上述方法使用new 并返回一个指向新分配的内存的指针,那么客户端(调用该方法的程序员)必须delete 内存。但是,如果方法返回的指针在调用其析构函数时被对象anotherObject 释放,则客户端不应释放指针所引用的内存。

    如果您是从 Java 开始接触 C++ 的新手,您绝对应该尽可能尝试使用references,并查看smart pointers。智能指针的好处在于它们提供了自动内存管理(您不必担心在 newed 对象后删除)。

    【讨论】:

    • +1,智能指针几乎总是在 C++ 中处理内存管理的最佳方式。
    • 处理动态内存分配的另一种最佳方法是不要使用它,除非你必须......相信我它运作良好!
    • 诚然,智能指针和 boost 指针容器是一个不错的选择,但不建议将它们用于必须运行 FAST 的程序。我的老板不介意让我们花两个月的时间用 Purify 调试我们的程序,前提是我们不使用智能指针。我自己尝试了一些程序,智能指针在我们的程序中占用了很多额外的毫秒,这涉及到大量的指针复制、创建和销毁。
    【解决方案4】:

    当您只是想学习基本的 C++ 内存管理时,忘记所有关于引用和智能指针的答案。

    学习基础知识,稍后您可以返回这些“高级”主题。

    【讨论】:

    • 感谢您的反对。这个人正在努力学习 new 和 delete 的基础知识,你想建议他使用智能指针。不错...
    • 我认为你有一个务实的答案,所以 1+。
    【解决方案5】:

    回答主题中的问题:在 C++ 中,您使用 delete [] 删除使用 new[] 分配的数组。即:

    int *a = new int[10];  // Allocate 10 ints and save ptr in a.
    for (int i=0; i<10; i++) {
        a[i] = 0;    // Initialize all elements to zero.
    }
    delete [] a; // Free memory allocated for the a array.
    

    正如 Gustavo 正确指出的那样,删除调用中 [] 的原因是确保在数组的每个元素中调用析构函数。

    【讨论】:

    • 这与帖子有什么关系?
    • 它与主题相关,但我不确定标题是否与问题的主体匹配..
    • 我要补充一点,[]delete 调用中的原因是为了确保在数组的每个元素中调用析构函数。
    • @Gustavo:用您的评论更新了答案。谢谢!
    【解决方案6】:

    如果不知道getSubObject() 的详细信息,就无法知道如何真正回答这个问题。答案应该getSubObject()的文档中(但不是每个人都遵循应该。)该文档可能在一些旧式文档中,一些doxygen(或类似) 页面,声明getSubObject() 的头文件。如果最坏的情况发生了,您需要查看定义getSubObject() 的源代码,假设源可用。

    在阅读该文档/标题/源代码时,您应该寻找“getSubObject() 是否分配调用者必须删除的内存,还是仅返回指向现有对象的指针?”问题的答案?像getSubObject() 这样的名字我希望是后者。如果函数的名称是createSubObject(),我希望是前者。

    【讨论】:

      【解决方案7】:

      对此没有正确答案。 如果成员函数(或使用 java 术语的方法)返回的指针指向 在堆栈中分配的对象,如果在其上使用关键字 delete,您的程序将崩溃。

      如果您使用空闲存储空间,应该由调用者还是被调用者负责内存管理?如果另一个人调用成员函数,现在你有一个悬空指针。如果被调用者正在使用 RAII 怎么办?

      既然您正在学习(对此表示敬意),请先尝试学习内存管理的基础知识。一旦您对内存有了基本的了解,您就会更熟悉 C++ 和内存管理。

      如果您正在编写生产代码,并且必须在 C++ 中进行。避免所有这些问题的最安全方法是仅在需要时使用动态内存分配,直到您对它有更好的理解。在我看来,即使您对动态内存分配有很好的了解,也应该有充分的理由使用它。

      祝你好运,

      阿曼多。

      【讨论】:

        【解决方案8】:

        在 C++ 中,您必须自己管理内存分配,没有像 java/C# 和任何其他现代语言那样忘记清理的位垃圾收集。如果您忘记了内存,充其量是泄漏,最坏的情况是您继续使用它,而其他东西却在使用它。这是一个很难解决的问题,如果有的话,C++ 程序员很少能做到这一点,因此使用智能指针和其他深奥的高级魔法来解决 C++ 中的这些问题。 @yi_H 是正确的,了解基本内存分配的基础知识,这样你就知道为什么智能指针是个好主意了。

        如果没有智能指针,虽然上面的一些答案已经避开了它,但“所有权”是最关键的要理解的事情。每当你有一个指向内存块的指针时,你必须知道谁拥有它。如果您拥有它,则必须在它超出范围或丢失之前将其释放。如果您给其他人一份它的副本,请确保您定义谁拥有它,以及所有者何时可以/将/应该释放它。如果你不能做到这一点,你就会被水洗。通常,C++ 库在记录这一点上是出了名的糟糕,因此在没有明确信息的情况下,假设您不拥有它(不要删除它并可能造成内存泄漏),而不是删除它并创建难以发现的缺陷.使用 Valgrind 查找工作程序的内存泄漏。

        为避免最严重的陷阱,请遵守一些简单的规则。优先使用局部变量和引用而不是堆(新)。在归还分配的内存时,清楚地记录分配的内存的所有权和生命周期。避免复制指向已分配内存的指针,尽可能复制数据。制作指针副本时,尽可能使范围小且生命周期短。以效率的名义大量使用指针(很糟糕)——运行缓慢的程序比随机转储内核的程序效率高。

        即限制关键字“new”的使用。

        【讨论】:

          【解决方案9】:

          那么设计不应该是这样,你从另一个对象中获取一个指针并删除它。

          SubObject *mySubObject = anotherObject.getSubObject();
          delete mySubObject;
          

          如果您在该点删除 mySubObject, anotherObject 类函数可能仍会使用它。您应该遵循 OOP 方法。 getSubObject() 函数返回的对象应该从构造函数创建/分配内存并在析构函数中释放。是的,这里的参考更好,这样就不会在课堂外错误地执行删除。谢谢。

          【讨论】: