指向已删除堆栈内存的指针

时间:2015-07-28 03:31:48

标签: c++ pointers memory

我相信我刚刚经历的事情被称为"未定义的行为",但我不太确定。基本上,我在外部作用域中声明了一个实例,该作用域包含一个类的地址。在内部级别,我在堆栈上实例化了一个对象,并将该实例的地址存储到持有者中。

内部范围转义后,我检查了是否仍然可以访问已删除实例的方法和属性。令我惊讶的是,它没有任何问题。

有没有一种简单的方法可以解决这个问题?有没有办法可以清除列表中删除的指针?

示例:

ArrayIndexOutOfBoundsException

2 个答案:

答案 0 :(得分:3)

  

有没有一种简单的方法可以解决这个问题?

当然,有很多方法可以避免这类问题。

最简单的方法是根本不使用指针 - 而是通过值传递对象。即在您的示例代码中,您可以使用std::vector<int>代替std::vector<int *>

如果您的对象由于某种原因无法复制,或者您认为复制它们太昂贵,您可以在堆上分配它们,并使用shared_ptr自动管理它们的生命周期unique_ptr或其他一些智能指针类。 (请注意,按值传递对象比您想象的更有效,即使对于较大的对象也是如此,因为它避免了必须处理堆,这可能很昂贵......而现代CPU在处理连续内存时效率最高。 ,现代C ++有各种优化,允许编译器在许多情况下避免实际进行数据复制)

通常,保留指向堆栈对象的指针是一个坏主意,除非您100%确定指针的生命周期将是它指向的堆栈对象的生命周期的子集。 (即便如此,这可能是一个坏主意,因为下一个程序员在你转到下一个工作后接管代码可能看不到这种微妙的危险,因此在更改时可能会无意中引入悬空指针错误代码)

  

在内部范围逃脱后,我检查了看是否还能   访问已删除实例的方法和属性。出乎我的意料   它没有任何问题。

如果对象所在的内存尚未被其他任何内容覆盖,那么会发生这种情况 - 但如果/当您取消引用无效指针时,肯定不依赖于该行为(或任何其他特定行为),除非你喜欢花费大量的时间与你的调试器追逐随机崩溃和/或其他奇怪的行为:)

  

有没有办法可以清除列表中删除的指针?

原则上,您可以将代码添加到对象的析构函数中,这些代码将遍历列表并查找指向自身的指针并将其删除。在实践中,我认为这是一种糟糕的方法,因为它耗尽了CPU周期,试图从一个错误中恢复,而这个错误首先不允许更好的设计。

顺便说一下,这不是主题,但您可能会感兴趣的是,Rust编程语言旨在检测并防止此类错误by catching it at compile-time。也许有一天C ++会得到类似的东西。

答案 1 :(得分:0)

没有删除指针这样的东西。指针只是一个数字,表示进程虚拟地址空间中的某个地址。即使堆栈帧早已消失,持有它的内存仍然可用,因为它是在线程启动时分配的,所以从技术上讲,它仍然是一个有效的指针,对你而言是有效的可以取消引用它并得到一些东西。但是由于它指向的对象已经消失,因此有效的术语将是悬空指针。道德是如果你有指向堆栈框架中对象的指针,就无法确定它是否有效,甚至不使用像IsBadReadPtr这样的函数(例如Win32 API)。防止此类情况的最佳方法是避免返回并存储指向堆栈对象的指针。

但是,如果您希望跟踪堆分配的内存并在不再使用后自动解除分配,则可以使用智能指针(std::shared_ptrboost::shared_ptr等)。