【问题标题】:why it is a disater to have a pointer or reference to an object has been returned back to the memory heap in c++ [closed]为什么在 C++ 中将对象的指针或引用返回到内存堆是一场灾难[关闭]
【发布时间】:2016-09-24 07:01:16
【问题描述】:

所以我知道堆是存储内存的地方。与堆栈不同,如果用户不删除堆,则堆保持存在。

但是,我对 “一个对象已返回到内存堆” 部分有疑问。 返回是否意味着对象已被释放?如果不是,为什么拥有指向该对象的指针/引用是一场灾难?

【问题讨论】:

  • 对不起,我还是不明白它与已经返回到内存堆部分的对象有什么关系?请问可以延长吗? @sashoalm
  • 是的,这意味着它已被释放。然而,内存可能仍然存在,并且在某个未指定的时间堆可能会将其重新用于后续分配。
  • @Steve 非常感谢!
  • 被释放的内存可以随时更改其内容(例如,它被分配给另一个存储所需内容的对象)并且您的指针现在指向包含垃圾数据的内存(从它的点查看)。

标签: c++


【解决方案1】:

首先,堆和栈不是 C++ 的概念。它们指的是在某些系统上管理的特定类型的内存。

其次,通常所说的“堆”在 C++ 中被称为“动态分配的内存”。

当程序释放动态分配的内存时(例如,在使用运算符 new 获得的东西上使用运算符 delete,在 C 的 malloc() 返回的指针上使用 free())时,内存不再存在你的程序关心,但指针值没有改变。在 C++ 标准的语言中,使用不再存在的指针或引用会产生未定义的行为。

实际上,内存可能实际存在于您的系统上,甚至仍由主机系统分配给您的程序。然而,一旦它被你的程序释放,就没有什么能阻止内存被重用了。您的程序可能使用运算符new 分配更多内存,因此之前释放的内存现在被您的程序用于其他用途 - 与原始用途完全无关。这本质上是危险的 - 结果可以是任何东西(松散地说,就是 C++ 标准中未定义行为的含义)。

操作系统也可能已恢复逻辑或物理内存(毕竟,您的程序已指示不再使用该内存)并将其分配给另一个程序。这对您的程序和已分配内存的其他程序都是危险的。这就是为什么大多数现代操作系统会阻止这种情况,例如如果操作系统检测到对它不再拥有的内存的访问,则强制终止您的程序。

真正的危险是您可能会在一段时间内访问已释放的对象,而一切似乎都按要求工作。只会在以后崩溃。在您的程序释放一些内存和将其重新用于其他用途之间通常会有很长的时间间隔。

程序中的此类缺陷往往会激怒该程序的用户(由于某些晦涩的原因,当程序在工作过程中以不可预测和不可重复的方式崩溃时,用户往往不太欣赏)。代码中的此类缺陷也往往很难追踪,因此也很难纠正。

【讨论】:

    【解决方案2】:

    我对 “一个对象已返回内存堆” 部分有疑问。 返回是否意味着对象已被释放?如果没有,为什么拥有指向该对象的指针/引用是一场灾难?

    分解术语并澄清一些事情可能会有所帮助:

    首先,C++中的Object一词是指something驻留在内存中,而不是指内存本身。

    区分对象和存储对象的内存是值得的,因为分配内存和初始化对象的操作是不同的和独立的。

    下面这行做了两件事:

    new int(123);
    
    • 它将堆上的内存区域分配给您的程序,其字节大小等于sizeof(int)。内存分配的效果不是创建一个对象,甚至也不是改变该内存的内容;这只是为了让你的程序使用该内存。
      任何可能已经存在于该内存中的“垃圾”或垃圾值都不会被更改。

    • 分配内存后,该内存块将使用包含123int 对象进行初始化。对象只能在已分配给程序的内存区域内初始化。

    鉴于new 运算符正在执行两种不同的操作,因此delete 运算符也可以执行两种不同的操作:

    • delete 将销毁对象;这通常仅限于释放对象拥有的资源。销毁对象通常不会费心更改或重置任何即将被释放的内存,因为这通常会浪费 CPU 周期。
      对象被销毁后,您可能会发现该对象的残骸或部分残骸在内存中停留了一段时间,但就您的程序而言,对象本身已死/消失,内存内容是垃圾。

    • delete 将取消分配内存。解除分配的过程并不是要改变那块内存的内容,它只是释放那块内存供其他东西使用。在内存被释放后尝试访问该内存区域是未定义的行为。


    请记住,指针永远不能指向对象,因为对象是“内存中的事物”,而不是内存本身; C++ 中的原始指针相当简单/愚蠢——它们不跟踪任何关于对象在其指向的内存中的状态。如果一个对象被移动、复制或销毁,指针将一无所知。

    指针是内存中某个位置的地址

    想一想 pointer-values(地址)和包含这些值/地址的 pointer-variables 会有所帮助。遗憾的是,pointer 一词在历史上具有双重含义,既指指针值又指指针地址,这似乎令人困惑。

    通常,指针变量指向的内存位置应该在已分配的内存区域内包含有效对象,但也可能不包含。

    C++ 不会保护您免受悬空指针的影响,其中 悬空指针 是一个指针变量,其中包含尚未分配给程序的内存区域的地址。

    C++ 也不保护您免受指向未初始化内存的指针的影响(例如,如果您已使用 malloc 分配内存但未初始化其内容)。

    最后,C++ 不能保护您免受内存泄漏;作为程序员,您有责任跟踪您分配的所有内存。

    最后 3 点是 new/delete 在现代 C++ 中不经常使用的众多原因之一,以及为什么 & 引用、std::vectorstd::shared_ptr 和其他替代方法优先;他们处理新/删除周围的许多细微差别和陷阱。

    【讨论】:

      猜你喜欢
      • 2012-04-28
      • 2015-12-16
      • 1970-01-01
      • 2012-10-24
      • 2013-07-28
      • 2020-05-15
      • 2013-04-30
      • 2021-03-11
      • 1970-01-01
      相关资源
      最近更新 更多