繁体   English   中英

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

[英]Pointer pointing to deleted stack memory

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

逃脱内部作用域后,我检查是否仍然可以访问已删除实例的方法和属性。 令我惊讶的是,它没有任何问题。

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

例:

std::vector<int*> holder; 
{
    int inside = 12;

    holder.push_back(&inside);
}
cout << "deleted variable:" << holder[0] << endl;

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

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

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

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

一般来说,保留指向堆栈对象的指针是一个坏主意,除非您100%确保指针的生存期是它指向的堆栈对象的生存期的子集。 (即使那样也可能不是一个好主意,因为下一个在您从事下一份工作之后接管代码的程序员可能不会看到这种细微的危害,因此可能在对代码进行更改时无意中引入了悬空指针的错误。编码)

逃脱内部作用域后,我检查是否仍然可以访问已删除实例的方法和属性。 令我惊讶的是,它没有任何问题。

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

有什么方法可以清除列表中已删除的指针?

原则上,您可以将代码添加到对象的析构函数中,以遍历列表并查找指向自身的指针并将其删除。 实际上,我认为这是一种较差的方法,因为它会用尽CPU周期来尝试从错误中恢复,而错误最初是不允许进行更好的设计的。

顺便说一句,这不是主题,但您可能会感兴趣,Rust编程语言旨在通过在编译时捕获它来检测并防止此类错误。 也许有一天C ++会得到类似的东西。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM