在 C++ 中为已释放的内存分配一个值

Assigning a value to a deallocated memory in C++

我正在使用 http://www.learncpp.com. In the lesson on Dynamic memory allocation with new and delete (http://www.learncpp.com/cpp-tutorial/69-dynamic-memory-allocation-with-new-and-delete/) 中的教程学习 C++,它指出:

同样,当一个动态分配的变量被删除时,指向它的指针不会被清零。考虑以下片段:

int *pnValue = new int;
delete pnValue; // pnValue not set to 0

if (pnValue)
    *pnValue = 5; // will cause a crash

然而,当我尝试它时(编译器:GNU GCC 编译器,ubuntu),我的程序没有崩溃。

int *pnValue = new int;
delete pnValue; // pnValue not set to 0
if (pnValue)
    *pnValue = 5; // will cause a crash -> doesn't
std::cout << "Did not crash" << std::endl;

这里发生了什么? C++ 中是否有任何形式的运行时检查?

你的程序不会崩溃,因为你很幸运(或不幸,感谢@user1320881,因为你可能不会在更复杂的代码中检测到这些事情,并且可能会发生一些后来的崩溃或令人讨厌的副作用)。事实上,你在这里拥有的是未定义的行为,任何事情都可能发生(不一定是崩溃)。从技术上讲,您的程序不会崩溃可能是因为操作系统尚未回收那部分内存并且您没有覆盖属于其他进程的内存,但您永远不应该编写这样的代码。

编辑:经过几条评论 - 简短的回答 - 也许是最好的 - 是行为未定义。

C++ 在删除后不强制指针指向 NULL, 因此指针可能仍然具有并且很可能确实具有对已释放内存的内存引用。

如果内存引用确实存在,没有 NULL 指针异常,它可能不会崩溃,因为您对引用的内存所做的操作不会被注意到。

操作系统不会注意到无效引用,只要您只是使用堆中为您的进程分配的内存。如果删除操作会释放一些为堆保留的操作系统内存,它会崩溃,但这种情况不太可能发生。

C++ 库的堆管理器可能不会注意到 对已释放内存的访问 - 这取决于实现。

您自己的程序也可能不会受到影响,因为您还没有完成可能会重用刚刚释放的内存的分配。

C++ 编译器没有注意到这个 - 它也没有对内存分配的对象强制执行 运行 时间引用计数,也没有执行任何 运行-时间检查参考文献的有效性。编译器很高兴您将正确类型的变量分配给指针引用的内存

使用 C++ 时,内存分配不仅难以管理,而且可能会导致非常严重的问题。这就是为什么 reference counting 是一个很好的做法,它也可以与 C++ 一起使用,并带有专门的库。

欢迎使用 C++ 中的未定义行为。虽然您的问题已经得到直接回答,但由于您是该语言的新手,我建议您 John Regehr's blog post the C++ Super-FAQ entry 关于该主题。我相信他们会澄清很多你以后可能有的问题。