【问题标题】:c++ - Does allocating memory to an empty class casues memory leak?c++ - 将内存分配给空类会导致内存泄漏吗?
【发布时间】:2020-04-06 02:42:20
【问题描述】:

OctoMap代码中出现以下函数:

class AbstractOcTreeNode {}; -> 他们声明了一个空类

AbstractOcTreeNode** children; -> 这是在OcTreeDataNode 类头文件中声明的

template <typename T>
void OcTreeDataNode<T>::allocChildren() {
  children = new AbstractOcTreeNode*[8];
  for (unsigned int i=0; i<8; i++) {
    children[i] = NULL;
  }
}

这不会导致内存泄漏吗?不应该是:

template <typename T>
void OcTreeDataNode<T>::allocChildren() {
  children = new AbstractOcTreeNode*[8];
  for (unsigned int i=0; i<8; i++) {
    delete children[i];
    children[i] = NULL;
  }
}

我错过了什么?感谢您的帮助!

【问题讨论】:

  • new AbstractOcTreeNode*[8] 只是创建指针数组。该数组中包含的指针尚未指向AbstractOcTreeNode 的任何实例。
  • 实际上这些花括号之间有100行代码,其中有虚成员函数。它不是一个空的类。

标签: c++ memory-leaks empty-class octomap


【解决方案1】:

您希望删除整个数组,而不是每个单独的数组元素

template <typename T>
void OcTreeDataNode<T>::allocChildren() {
  children = new AbstractOcTreeNode*[8];
  for (unsigned int i=0; i<8; i++) {
    children[i] = NULL;
  }

  // .... later
  delete[] children ;
}

您必须始终将newdelete 匹配,并将new[]delete[] 匹配,不要混合使用它们。

为了完整起见(我猜测上下文),因为函数的名称是 allocChildren 我假设他们打算 new[] 数组并且 清理内存,但是.希望以后会有一个匹配的deallocChildren delete[] 这个内存。

【讨论】:

  • 真的吗? children 似乎是一个成员变量,而一个名为 allocChildren 的函数在退出时释放内存似乎非常具有误导性。
  • @NathanOliver-ReinstateMonica 我也是这么想的。添加了一条评论来解决这个问题。
  • 我希望清理工作在OcTreeDataNode&lt;T&gt;::~OcTreeDataNode&lt;T&gt;() TBH 进行。
  • 实际上它metnions:树类管理这个指针、数组和它的内存!
【解决方案2】:
AbstractOcTreeNode** children;

children 可以看作是一个指针值数组。

children = new AbstractOcTreeNode*[8];

我们用一个包含八个指针值的数组来初始化它。

for (unsigned int i=0; i<8; i++) {
    children[i] = NULL;
}

八个children[i] 指针值中的每一个最初都是未初始化的AbstractOcTreeNode*。我们将NULL 值分配给它们中的每一个。事先在这些未初始化的指针上调用delete 将是未定义的行为。

只有一次内存分配(new[] 只调用一次),其结果保存在children 中。只要children最终被清理就没有泄漏(使用delete[],大概在OcTreeDataNode&lt;T&gt;的析构函数中)。

您的困惑是拥有多个级别的指针的结果,至少其中一些是拥有的。因此,我个人也发现此代码难以阅读。在现代 C++ 中,您不会执行手动内存管理,无论是分配指针数组(std::vectorstd::array 怎么样)或分配每个 AbstractOcTreeNode-dervied 实例(此处未显示)。您可能会在现代 C++ 中找到 std::vector&lt;std::unique_ptr&lt;AbstractOcTreenode&gt;&gt; children;

【讨论】:

  • “每个 children[i] 指针值最初都是一个未初始化的 AbstractOcTreeNode*”。那么他们为什么要设置 children[i] = NULL;为每个孩子。此外,所以如果我想稍后将一个新的孩子实际设置为 OcTreeDataNode 对象,我应该使用: children[i] = new OcTreeDataNode; ?
  • 另外,如果 AbstractOcTreeNode 不是一个空类,这是否是正确的方法?即 children = new AbstractOcTreeNode*[8];只分配指针而不为类对象分配空间?所以我不能使用 children[i],在我设置 children[i] = new AbstractOcTreeNode; ?
  • @RonD 将其设置为NULL 比保持未初始化更可取。取消引用nullptr 很可能会立即使程序崩溃,取消引用随机内存值会导致混乱和痛苦。另外,在nullptr 上调用delete 很好并且什么都不做,而在未初始化的值上调用delete 是UB。是的,new OcTreeDataNode 可能是获取要放入其中的指针的一种方法。文档是怎么说的?
  • 您的第二条评论是正确的。 new AbstractOcTreeNode*[8] 只是分配空间来保存八个指针值。
【解决方案3】:

分配内存并立即删除它是什么意思?

template <typename T>
void OcTreeDataNode<T>::allocChildren() {
  children = new AbstractOcTreeNode*[8];
  for (unsigned int i=0; i<8; i++) {
    delete children[i];
    children[i] = NULL;
  }
} 

上面的函数没有意义。

注意空类的大小不为零。

并且分配了一个指向空类的指针数组。类的对象没有在这个函数中分配。

在这个函数中

template <typename T>
void OcTreeDataNode<T>::allocChildren() {
  children = new AbstractOcTreeNode*[8];
  for (unsigned int i=0; i<8; i++) {
    children[i] = NULL;
  }
}

命名空间中定义的变量children在成员函数中获取分配数组的地址。

所以其他一些代码负责释放分配的内存。

一般来说,类的成员函数使用全局变量是个坏主意。

【讨论】:

    猜你喜欢
    • 2019-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-14
    • 2017-08-31
    • 2021-03-23
    • 2021-09-25
    • 2014-12-08
    相关资源
    最近更新 更多