为什么我不应该在“删除”之后尝试使用“this”值?

时间:2009-12-08 11:48:05

标签: c++ undefined-behavior

讨论了this paragraph of C++ FAQ delete this构造的用法。列出了4个限制。

限制1到3看起来很合理。但是为什么限制4在那里我“必须不检查它,将它与另一个指针进行比较,将它与NULL进行比较,打印它,投射它,用它做任何事情”?

我的意思是this是另一个指针。为什么我reinterpret_cast无法int或致printf()输出其值?

7 个答案:

答案 0 :(得分:37)

调用delete之后'this'的值是未定义的,并且您对它执行的任何操作的行为也是未定义的。虽然我希望大多数编译器做一些合理的事情,但是没有(在规范中)阻止编译器决定它在这种特定情况下的行为将发出代码来格式化你的硬盘。调用未定义的行为(几乎)始终是一个错误,即使您的特定编译器按照您希望的方式运行。

你可以通过在调用delete之前获取指针的副本(作为整数)来解决这个问题。

答案 1 :(得分:29)

在删除指针(此指针或任何其他指针)后无法对指针执行任何操作的原因是硬件可能(以及一些较旧的计算机)陷阱尝试将无效的内存地址加载到寄存器中。尽管它可能适用于所有现代硬件,但标准规定,对无效指针(未初始化或删除)唯一可以做的是分配给它(NULL或来自另一个有效指针)。

答案 2 :(得分:28)

啊哈!

3.7.3.2/4:“...释放函数应解除分配指针所引用的存储,使所有指针无效,引用解除分配存储的任何部分。使用无效指针值的效果(包括传递它)解除分配函数)未定义“。

请注意,这表示“使用值”,而不是“取消引用指针”。

该段落并非特定于this,它适用于已删除的任何内容。

答案 3 :(得分:3)

因为您可以使用该指针执行的任何操作都可以触发在该对象的类方法上解释的逻辑,这可能会导致崩溃。

现在,你指出的一些行动显然是“安全的”,但很难说你可以调用的任何方法中会发生什么。

从帖子:“一定不要检查它,将它与另一个指针进行比较,将它与NULL进行比较,打印,投射,用它做任何事情”?

所有这些操作都可以触发与操作员相关的函数,这些函数使用未定义的指针进行计算。同意铸造。

现在,如果你执行reintepret_cast,这可能是一个不同的故事,你可能可以相处,因为重新解释只是一点一点点重新解释,而不涉及(据我所知)任何方法调用。

答案 4 :(得分:2)

出于同样的原因,你不会删除任何其他指针,然后尝试对它执行任何操作。

答案 5 :(得分:1)

b / c现在引用的地址,未定义,你不知道那里有什么......

答案 6 :(得分:1)

在多线程程序中,当你delete指针时,可用空间可以被另一个线程分配,覆盖this使用的空间。即使在单线程程序中,除非您在return之前对所调用的内容非常小心,否则在delete this之后执行的任何操作都可以分配内存并覆盖{{1}过去指向的内容}}

在以调试模式编译的Microsoft Visual C ++可执行文件中,this指针导致其内存立即被0xCC测试模式覆盖(未初始化的变量也使用此模式初始化),以帮助识别悬空像这样的指针错误。

这让我想起当我修复了在线可玩游戏中的一个错误,其中Fire对象的构造函数删除了最老的Fire,如果Fires的总数达到了一定数量。删除的Fire有时是父Fire创建一个新的Fire - bam,悬空指针bug!只是由于幸运,这个错误以完全可预测的方式与内存分配算法交互(删除的Fire总是以相同的方式用新的Fire覆盖) - 否则会导致在线玩家之间的不同步。在重写游戏进行内存分配的方式时,我发现了这个错误。由于其可预测性,当我修复它时,我还能够实现其行为的仿真以与旧游戏客户端兼容。