指向已删除的堆栈内存的指针
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_ptr
, boost::shared_ptr
等)。
- 从堆栈分配的原始指针构造智能指针
- 使用指针计算堆栈问题的大 O 表示法
- 作为指针注入类后重新创建堆栈对象不好吗?
- 如何模板化堆栈分配的多态指针数组到接口,包括派生类型的相应点?
- 如何按指针查看堆栈跟踪
- 堆栈/帧指针作为外部变量
- 未分配被释放的指针(将堆栈实现为链表时)
- 唯一指针是否在堆或堆栈上分配内存?
- 了解通过引用传递取消引用指针时C++堆/堆栈分配
- C++设置堆栈指针
- 启用优化时的堆栈指针比较异常
- 从堆栈指针中查找函数参数值
- 分叉进程的零星堆栈指针分段错误
- Ostream操作员Strangley不接受我的堆栈指针
- 如何展开堆栈以获取指定堆栈指针(SP)的回溯
- 删除具有堆栈指针的派生类
- 基于整数的函数递增/递减堆栈指针
- 使用c++,我如何获得堆栈指针的值在msvc X64
- 通过创建局部变量减少堆栈指针
- 是堆栈指针,是伪随机数的良好来源