我应该删除来自其他函数或类方法的指针吗?

时间:2018-01-08 13:11:41

标签: c++ pointers posix heap-memory

我有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分配它们?但是如果它错了怎么能确保在我使用完它们之后将其他方法分配的内存删除?

4 个答案:

答案 0 :(得分:4)

不一定。

C ++中不可避免的规则是每个new需要与delete配对,每个new[]配置delete[]mallocfree,&amp; c。仍然可用。

因此,假设您需要通过readdir的显式调用释放从delete返回的内存,但可能,这很诱人不是这样的:

  1. 它可能已经分配了new[],甚至是malloc

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

  3. 如果库有说服力与C ++标准库配合使用,它可能会为您提供删除器:您可以将构造传递给智能指针< / em>例如std::unique_ptr

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

    黄金法则是检查文档并执行它告诉您的操作。

答案 1 :(得分:4)

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

一般来说,你总是要查阅给你一个指针的函数手册,它还指明了如何解除分配它。

只是为了给你一个想法:

  • malloc / calloc / realloc→free

  • fopen→fclose

  • X ...→XFree

答案 2 :(得分:3)

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

答案 3 :(得分:3)

C与C ++不同,特别是在这方面。

当使用某些外部库提供的某些外部C(或C ++)功能时,您应阅读其文档遵循“所有权”规则和 < EM>约定 即可。例如,如果您使用getline,则了解您需要free here。如果您使用opendir,则应使用closedir。如果您使用sqlite3_prepare_v2,则需要sqlite3_finalize等等...有时您会考虑abstract data type(如here)和{{destructor。 3}} - 就像功能一样。

当您在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 sanitizerGCCinstrumentation optionsClang之类的工具)实际上非常有助于追捕{{3和其他一些内存错误。还要注意memory leaks。请注意了解ASLRvirtual address space。在Linux上,请阅读process,然后在某个终端尝试cat /proc/$$/mapscat /proc/self/maps,以获得有用的见解。