【问题标题】:Should I delete pointers that come from other functions or class methods?我应该删除来自其他函数或类方法的指针吗?
【发布时间】:2018-06-17 11:23:55
【问题描述】:

我有 Java 方面的背景,但我还没有完全习惯指针和范围的概念,如果这个问题看起来很愚蠢,请见谅。

我在某处读到我应该删除在堆上分配的指针。我明白这一点,但我是否也应该删除这样给我的指针:

#include<dirent.h>

DIR* dir;
struct dirent* entries;

dir= opendir("D:/DIR")
entries= readdir(entries)

// Should I delete the pointers after I'm done with them?
delete entries;
delete dir;

我应该删除从其他地方分配的指针还是超出范围自动删除它们?

或者删除它们是否正确,因为我没有使用new 分配它们?但是,如果它是错误的,我如何确保从其他方法分配的内存在我用完它们后会被删除?

【问题讨论】:

  • 您需要阅读每个函数的文档。 #include&lt;dirent.h&gt; 哪里不是标准的C++C
  • deletenewdelete[]new[]。并且你永远不应该delete 任何未使用new 分配的东西,例如使用malloc 分配的内存。并且如在例如this readdir manual page 你应该 free 返回的指针。你也不应该释放opendir 返回的指针,而是应该像文件一样关闭它,使用closedir。网络上的任何例子都应该告诉你。
  • 今后,请不要发送带有语言标签的垃圾邮件。仅使用您实际编程的语言。在您的情况下,它应该只是 c++ 标记。
  • 在这种情况下,这些指针是由函数调用自动分配的,因此您无需删除它们或担心,但您必须调用各自的关闭函数,例如closedir()。此外,如果您检查man readdir,则表明您不应释放此函数调用返回的指针。

标签: c++ pointers posix heap-memory


【解决方案1】:

不一定。

C++ 中不可避免的规则是每个new 都需要与delete 配对,每个new[] 都需要与delete[] 配对,并且mallocfree 等。仍然可用。

因此很容易假设您从readdir 取回的内存需要通过显式调用delete 来释放,但可能并非如此:

  1. 它可能被分配了new[],甚至malloc

  2. 该库可能提供了一个您需要调用的函数来释放内存。

  3. 如果库有说服力与 C++ 标准库一起工作,它可能会为您提供 删除器:您可以将构造传递给 智能指针 比如std::unique_ptr

我认为 (2) 最有可能也是最明智的,因为不同的 C++ 运行时环境可能会以不同的方式执行 newdelete。 (3) 是这个概念的扩展,如果他们支持它,那么就使用它。

黄金法则是检查文档并按照它告诉你的去做。

【讨论】:

    【解决方案2】:

    这个问题没有明确的答案,因为它总是取决于分配内存的语义。例如,在您提供的代码示例中,您必须不要使用 delete 进行释放,因为 opendir 不是 C++ 函数(而是 POSIX 函数)并且要正确关闭它,您调用 @ 987654323@。然后可以丢弃指针本身(不需要删除,closedir 在内部进行清理)。只要确保你在释放后不使用它(参见:use-after-free-bug)。

    一般来说,您必须查阅提供指针的函数手册,其中还明确指定了如何释放它。

    只是给你一个想法:

    • malloc/calloc/realloc → 免费

    • fopen → fclose

    • X… → XFree

    【讨论】:

      【解决方案3】:

      C 与 C++ 不同,尤其是在这方面。

      当使用某些外部库提供的某些外部C(或C++)函数时,您应该阅读其文档遵循“所有权”规则和约定。例如,如果您使用getline,您就会明白您需要free,例如here。如果你使用opendir,你应该使用closedir。如果你使用sqlite3_prepare_v2,你就需要sqlite3_finalize,等等……有时你会想到一些abstract data type(比如here)和destructor-like函数。

      当您在 C 中开发您自己的(公共或“私有”)函数时,您需要记录它是否返回堆分配的内存以及谁(以及如何)是负责free(或发布)它。

      使用 C++,您还拥有smart pointersRAII;所以你通常可以避免手动newdelete。智能指针很有帮助,但not a silver bullet

      所以您应该显式记录约定(并遵循外部库和API的约定)关于所有权。理解和明智地定义这些约定是一项重要的任务。

      Circular references 难以处理(在适用时考虑weak pointers)。我建议阅读垃圾收集概念和技术(例如GC handbook),至少能够正确命名您的方法并了解reference counting 的局限性和强大功能。在某些情况下,您甚至可以显式使用garbage collector library 或编写自己的分配器。

      Manual memory management 是一个完整的程序属性,这就是为什么它很难。甚至在某些情况下(长期存在的进程进行大量分配)您需要害怕fragmentation

      valgrindaddress sanitizer 之类的工具(以及GCCinstrumentation optionsClang 的工具)实际上对寻找memory leaks 和其他一些内存错误非常有帮助。还要注意ASLR。注意了解processvirtual address space。在 Linux 上,阅读proc(5),然后在某些终端中尝试cat /proc/$$/mapscat /proc/self/maps,以获得有用的见解。

      【讨论】:

        【解决方案4】:

        最终你应该查阅供应商的手册,看看他们的函数是否自己进行清理,或者你需要调用另一个函数来进行清理等。一般来说,在 C++ 中谈论 raw 指针时,你应该在适当的地方显式释放分配的内存。无论是来自函数还是来自new / new[] 运算符都没有区别。要避免这种new / delete 组合,您可以使用smart pointersRAII 技术。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-10-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-07
          相关资源
          最近更新 更多