【问题标题】:What happens if i don't free/delete dynamically allocated arrays?如果我不释放/删除动态分配的数组会怎样?
【发布时间】:2013-08-31 10:47:27
【问题描述】:

这段代码不是我写的! 在 WebServer 类中,我们重载了 +=operator。该类使用动态分配的 WebPage(另一个类,组合)类型的对象数组,定义为 WebPage *wp;

WebServer & operator +=( WebPage webPage ) {
WebPage * tmp = new WebPage [ count + 1];
for (int i = 0; i < count ; i ++)
tmp [i] = wp[i];
tmp [ count ++] = webPage ;
delete [] wp;
wp = tmp;
return * this ;
}

所以我们创建了一个新的动态分配的 WebPage 数组,其中一个对象具有额外的空间,然后我们将 wp 保存的值分配给它们,然后将我们想要添加到数组中的对象分配给它们。所以如果我删除delete[] wp;,程序仍然可以正常工作。那么如果我删除那行代码会发生什么?还有wp=tmp,这是什么意思,wp只是动态的一个新名称,所以它适合类中的名称,但内存中的位置仍然相同?还是?

【问题讨论】:

  • 如果您不释放/删除动态分配的数组,它们不会被释放/删除。就是这样。
  • 使用vector&lt;WebPage&gt;它会自动删除自己,并有一个push_back函数来向现有数组添加新元素。
  • 当你不删除动态分配的内存时,一个可怕的诅咒就会发生,你的手指和你触摸的任何东西都会变成金子......鱼。所以你不能再写代码了。而且你必须把手放在水下。

标签: c++ class object dynamic-allocation


【解决方案1】:

所以如果我删除 delete[] wp;该程序仍然可以正常工作。所以呢 如果我删除那行代码会发生什么?

您介绍了memory leak。每次调用此运算符时,该进程都会浪费其地址空间的一部分,直到最终耗尽内存。

还有wp=tmp,这是什么意思,wp只是一个新名字 动态,因此它适合类中的名称,但位置 记忆中还是一样的吗?还是?

wp 可能是WebServer 的成员(一个实例变量),它保存了它所服务的WebPage 对象的实例。所以该行正在用一个新值(包括刚刚添加到服务器的网页)替换之前的网页数组。

想必还有WebServer的其他成员函数读取wp里面的值并用它们做事。

作为一般说明,您应该知道这段代码写得非常糟糕,因为它甚至不是远程异常安全的,它正在做的工作可以通过相当智能的实现来避免,而且最重要的是它使用自制代码代替标准语言设施,如std::vector

【讨论】:

  • 我想再为您帖子的最后一行 +1。那段代码真的让我不寒而栗。它不仅难以阅读,而且在运行时效率低下,在标准库(向量)存在的情况下编写效率低。
  • 等一下,所以我们释放 wp,然后用 wp=tmp 我们再次用一个 exrea 对象占用它,当函数结束时 temp 会自行销毁?
  • 还有你会怎么写代码,我不知道有什么其他的写法所以......
  • @StefS: tmp 不会破坏自己,因为它是一个哑指针。它指向的内存也不会破坏自己,因为它是用new[]分配的;在调用 delete[] 之前,它的生命周期不会结束,这将在下次调用此运算符 (delete[] wp) 时发生。
  • @StefS:写这篇文章的更好方法是使用std::vector&lt;WebPage&gt; 而不是wp;操作员不仅会更加健壮,而且会更单行:vector.push_back(webPage); return *this;。但这当然意味着所有触及wp 的代码都必须相应更改。
【解决方案2】:

任你选择:

  • 只是内存泄漏或
  • 内存泄漏行为未定义,具体取决于您的类的析构函数是否包含具有副作用的代码。

在这种情况下,它只会导致内存泄漏。但是,取决于相同的未分配内存是否被其他对象重用,您最终可能会出现未定义的行为。

C++11 标准:[basic.life](3.8 对象生命周期),第 4 段:

程序可以通过重用对象占用的存储空间或通过显式调用具有非平凡析构函数的类类型对象的析构函数来结束任何对象的生命周期。对于具有非平凡析构函数的类类型的对象,在重用或释放对象占用的存储空间之前,程序不需要显式调用析构函数;但是,如果没有显式调用析构函数或者如果没有使用删除表达式 (5.3.5) 来释放存储,则不应隐式调用析构函数,并且生成任何依赖于副作用的程序析构函数具有未定义的行为。

【讨论】:

  • 我不确定这是未定义的行为。
  • 这绝不是未定义的行为。
  • @R.MartinhoFernandes:永远不要说永远 :)
  • @AlokSave:我没有查找标准以获取更多上下文,但这一段似乎是在说如果你重用内存而不破坏以前的占用者,就会发生坏事第一的。这里没有重用内存。
  • 那句话不相关:S 它是关于在现有对象之上就地构造新对象的程序(又名“重用存储”),例如 ::new (&amp;existing) T;
【解决方案3】:

不调用delete意味着free不会被调用,析构函数也不会被调用。不在分配的内存上调用free 的含义是内存泄漏——您的程序不再可以使用该内存。如果这种情况持续存在,随着时间的推移,您的程序很可能会因为内存不足而崩溃,不调用 dtor 意味着您的数组使用的任何其他资源(更多内存、数据库连接、)是也输了。

【讨论】:

  • +1 用于提及可能在析构函数中以 RAII 样式释放的其他资源。
【解决方案4】:

如果您不删除某些内容,则会发生内存泄漏。内存泄漏属于“它持续工作了很长一段时间,但随后失败”的损坏代码类别。这使得它们难以处理,因为问题发生在原始错误之后很长时间,并且通常很难确定内存泄漏的位置/方式,并且当没有更多内存时,应用程序在某个“随机”位置失败可用的。

当应用程序泄漏内存时,对其他应用程序也不利,因为其他应用程序可用的内存将减少。

根据泄漏的规模,它可能最终成为导致您的应用程序在可靠性方面声誉不佳的原因之一(“两天后崩溃”),或者它可能最终成为您应用程序的杀手(“当我尝试更复杂的用例时不起作用”)。或者可能只是在连续使用两年后,该应用程序的内存使用量从 64MB 增加到 72MB,因为在整个方案中,泄漏是如此之小,你并没有真正注意到。

但是发生内存泄漏从来都不是一件好事,而且在很多情况下是一件非常糟糕的事情。

【讨论】:

    【解决方案5】:

    使用new 分配的对象会一直保留在堆上,直到使用delete 释放它们。如果您不删除它们,它们将保留在那里(但无法访问 -> 这称为内存泄漏),直到您的进程退出,操作系统将释放它们。

    【讨论】:

      【解决方案6】:

      这可能是一个糟糕的代码,但我不知道使用字符串和向量(idk 为什么他们没有教我们),但我还是不太明白。是不是用WebPage * tmp = new WebPage [ count + 1];拳头占用了新空间,然后我们传输数据,然后我们删除wp。那么wp = tmp; 做了什么。是不是只给 tmp 占用的空间命名为 wp 以便与类中的名称相对应,但是这些对象的地址与 tmp 使用的相同,但与 wp 在被删除之前使用的不同? 比如:

      【讨论】:

        猜你喜欢
        • 2021-06-06
        • 2019-07-08
        • 1970-01-01
        • 2012-01-08
        • 2011-10-21
        • 1970-01-01
        • 2019-11-30
        • 1970-01-01
        相关资源
        最近更新 更多