以下代码访问不再分配的内存。
#include <stdio.h>
int main()
{
int * ptr = new int(5);
delete ptr;
return *ptr;
}
指针访问不再分配的内存,但直到内存可访问它才会返回一个值。 我想知道,实际上程序是否可能因分段违规信号而崩溃。
编辑:我在程序循环中运行超过100000次没有崩溃,这并不意味着它永远不会崩溃,只是它没有在这些期间崩溃100000次。也许用这么简单的程序是不可能的?
答案 0 :(得分:6)
我想知道这是否有可能导致程序崩溃,发生分段违规信号或类似事情。
是。取消引用已删除的指针是未定义的行为。可能发生的一件事就是崩溃。另一个是该程序可以毫无问题地默默退出。
答案 1 :(得分:3)
ptr仍包含内存地址。是否在进程上下文中访问此特定地址取决于操作系统的内存管理状态以及系统的C ++编译器的堆管理是否可能返回由于删除操作系统内存管理而释放的内存。如果它消失了,你会看到一个段违规。
但是很可能仍然可以访问该地址,并且您的程序不会因非法侵入而终止。但即使这是肯定的,您也无法保证从main返回的值仍然是变量在删除之前保留的值。堆内存管理是一个非常复杂的软件,并且无法确定返回时内存块会发生什么。
最后,如果你的程序使用线程,另一个线程可能已经请求了内存,并且接收并更改了几纳秒之前返回的内容。
所以:不要,永远不要!
答案 2 :(得分:2)
你的例子实际上太简单了,但不会崩溃。为了使您的示例崩溃,您的进程(标准C库)必须在delete
命令中将内存返回到操作系统。由于今天大多数系统上的内存都是organized in pages,因此您必须分配足够大的内存,以便在释放时,整个页面被释放并返回到操作系统。当您访问未映射的内存时会发生分段错误 - 这是返回到操作系统的内存的情况。但是,您要分配太小的内存量才能实现。
如果您想要崩溃,请给系统更多机会:)
#include <stdio.h>
#include <string.h>
// number of megabytes you will allocate
#define N 100
int main()
{
char *ptr[N];
int i;
for (i = 0; i < N; i++) {
ptr[i] = new char[1*1024*1024];
}
// if you remove the following loop, it won't crash
for (i = 0; i < N; i++) {
delete ptr[i];
}
return ptr[0][2000];
}
每次在我的系统上崩溃。即使在你的情况下,如果你的int
只是该页面上的最后一件事(可能不一定,取决于标准C库的实现),它可能会崩溃,但是需要很多机会,及其实施依赖。
我刚刚为您创建了更可能的崩溃案例,实际上相信可能会发生: - )
答案 3 :(得分:1)
是的,你应该从不处理释放的内存。
释放或删除堆分配内存后,使用未定义的系统行为。
有时它可能似乎可以正常工作,有时它不起作用,具体取决于您释放的已释放内存。
答案 4 :(得分:0)
因分段违规而崩溃的案例(基于Thomas的例子)可能是:
#include <stdio.h>
#include <string.h>
int main()
{
size_t size = 1024*1024;
char *ptr = new char[size];
memset(ptr,255,size);
delete [] ptr;
return ptr[0];
}
答案 5 :(得分:-1)
C标准只表示引用释放的指针是未定义的行为。它并没有说必须崩溃。它没有说明应该发生什么。
您必须了解“删除”实际上是做什么的。操作系统可能懒得删除内存,并将其标记为免费供可用,但由于没有其他进程在'delete ptr'和'return ptr'之间取得了这个内存的所有权,因此我并不感到惊讶不要在这里发生错误。
但同样,你的问题不能再回答,而是说它是未定义的行为。 baheviour的含义取决于实现和操作系统,并且是随机的和不可预测的(例如依赖于另一个有时间在删除和返回之间适当存储的进程)。