为什么我不应该在“删除此”之后尝试使用“此”值?
-
18-09-2019 - |
题
在 C ++常见问题解答 使用 delete this
讨论了构造。列出了4个限制。
限制1至3看起来很合理。但是,为什么我必须“不得检查它,将其与另一个指针进行比较,将其与空作品进行比较,打印,施放,对它做任何事情”?
我是说 this
是另一个指针。我为什么不能 reinterpret_cast
到一个 int
或打电话 printf()
输出其值?
解决方案
删除指针(此或任何其他指针)之后,您无法使用指针进行任何操作的原因是,硬件可以(以及某些较旧的机器)诱捕试图将无效的内存地址加载到寄存器中。即使在所有现代硬件上可能都很好,标准说,您唯一能做无效的指针(非初始化或删除)的事情就是分配给它(null或其他有效的指针)。
其他提示
调用删除后的“此”的价值是不确定的,并且您对其所做的任何事情的行为也是不确定的。虽然我希望大多数编译器都会做一些明智的事情,但(规格中)没有什么阻止编译器决定其在这种特殊情况下的行为将是发射代码以格式化您的硬盘。即使您的特定编译器以您喜欢的方式行事,调用不确定的行为(几乎)总是一个错误。
您可以通过在调用DELETE之前将指针的副本(作为整数)副本(作为整数)来解决此问题。
啊!
3.7.3.2/4:“ ... DealLocation函数应交易给指针引用的存储空间,使无效的所有指针都引用了交易量的存储的任何部分。使用无效的指针值(包括将其传递给DealLocation)功能)是不确定的。
请注意,这说明“使用值”,而不是“使用指针”。
该段不是特定于 this
, ,它适用于已删除的任何内容。
因为您可以使用该指针采取的任何动作都可以触发逻辑,该逻辑可以在该对象的类方法上解释,这可能导致崩溃。
现在,您指出的某些动作显然可能是“安全的”,但是很难说出您可以调用的任何方法发生什么。
从帖子中:“不得检查它,将其与另一个指针进行比较,将其与Null进行比较,打印,铸造,对其做任何事情”?
所有这些操作都可以触发与操作员相关的功能,这些功能通过未定义的指针进行评估。铸造的同上。
现在,如果您执行reintepret_cast,那可能是一个不同的故事,您可能会相处,因为重新解释只是重新解释,而无需(据我所知)任何方法调用。
出于同样的原因,您不会删除任何其他指针,然后尝试对其进行任何操作。
b/c现在指的是未定义的地址,您不知道会有什么...
在一个多线程程序中,您的那一刻 delete
指针,可自由空间可以由另一个线程分配,覆盖由 this
. 。即使在单线程程序中,除非您非常谨慎对待 return
ing,您之后所做的任何事情 delete this
可以分配内存并覆盖以前指向的内容 this
.
在Microsoft Visual C ++以调试模式编译的可执行文件中, delete
指针导致其内存立即被0XCC测试模式覆盖(也使用此模式初始化了非初始化的变量),以帮助识别诸如此类的悬空指针错误。
这让我想起了我在在线播放游戏中修复错误时,如果火灾总数达到一定数量,则火对象的构造函数删除了最古老的火灾。删除的火有时是父母大火造成新的大火 - BAM,悬挂的指针虫!正是由于运气,此错误以一种完全可预测的方式与内存分配算法进行了交互(删除的火灾总是以相同的方式覆盖新的火) - 否则,它将在线玩家之间引起不同步。在重写游戏进行内存分配的方式时,我发现了这个错误。由于它的可预测性,当我修复它时,我还能够实施其行为的模仿,以与较旧的游戏客户端兼容。