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

Should I delete pointers that come from other functions or class methods?

我有 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 分配它们?但是,如果它是错误的,我如何确保在我使用完其他方法后分配的内存会被删除?

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

不一定。

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

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

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

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

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

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

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

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

当使用某些外部库提供的某些外部 C(或 C++)函数时,您应该阅读其文档遵循 "ownership" 规则和 约定。例如,如果您使用 getline you understand that you need to free like here. If you use opendir you should use closedir. If you use sqlite3_prepare_v2 you'll need to sqlite3_finalize it, etc... Sometimes you'll think in terms of some abstract data type (like ) with a destructor-like 函数。

当您开发您自己的(public或"private")C函数时,您需要文档 如果它 returns 堆分配内存以及谁(以及如何)负责 free(或释放)它。

使用 C++,您还有 smart pointers and RAII; so you generally can avoid manual new and delete. Smart pointers are helpful, but not a silver bullet

所以你应该显式文档约定(并遵循外部库的约定和 API)关于所有权。明智地理解和定义此类约定是一项重要任务。

Circular references are difficult to handle (consider weak pointers when applicable). I recommend reading about garbage collection concepts and techniques (e.g. the GC handbook), to at least be able to name appropriately your approaches and understand the limitations and power of reference counting. In some cases, you might even explicitly use a garbage collector library 或编写您自己的分配器。

Manual memory management is a whole program property, and that is why it is hard. There are even cases (long-living processes doing a lot of allocation) where you need to be afraid of fragmentation.

valgrind and the address sanitizer (with GCC's instrumentation options or Clang's ones) are practically very helpful to hunt memory leaks and some other memory bugs. Be also aware of ASLR. Take care to understand the virtual address space of your process. On Linux, read proc(5) 这样的工具然后在一些终端中尝试 cat /proc/$$/mapscat /proc/self/maps 以获得有用的见解。

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

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

只是给你一个想法:

  • malloc/calloc/realloc → 免费

  • fopen → fclose

  • X…→ XFree