为什么我不应该在“删除这个”之后使用“this”值?
在这个C ++ FAQ的使用中delete this
构造。 列出了4个限制。
限制1至3看起来相当合理。 但为什么我不能检查它,把它和另外一个指针比较,把它与NULL比较,打印出来,然后用它来做任何事情呢?
我的意思是this
是另一个指针。 为什么我不能reinterpret_cast
到一个int
或调用printf()
来输出它的值?
删除指针(或其他指针)之后,不能用指针做任何事的原因是,硬件可能(以及一些较老的机器)会试图将无效的内存地址加载到寄存器中。 尽pipe在所有现代硬件上都可能没有问题,但标准还是说,对无效指针(未初始化或删除)唯一可以做的就是分配给它(NULL或从另一个有效指针)。
调用delete之后的“this”的值是未定义的,并且您使用它的任何行为也是未定义的。 虽然我希望大多数编译器做一些明智的事情,但在编译器中没有任何东西可以阻止编译器决定在这种情况下它的行为将发出代码来格式化硬盘。 调用未定义的行为(几乎)总是一个错误,即使你的特定编译器按你喜欢的方式行事。
在调用delete之前,可以通过获取指针的副本(作为整数)来解决此问题。
啊哈!
3.7.3.2/4:“…释放函数应释放指针引用的存储空间,使所有指向释放存储空间的指针无效。使用无效指针值(包括将其传递给释放function)未定义“。
请注意,这表示“使用该值”,而不是“取消引用指针”。
该段不是特定this
,它适用于任何已被删除。
因为你可以用这个指针进行的任何操作都可以触发在该对象的类方法上被解释的逻辑,这可能导致崩溃。
现在,你指出的一些行动可能显然是“安全的”,但很难说出你可以调用的任何方法中发生的事情。
从post:“不能检查它,与另一个指针进行比较,与NULL比较,打印,投它,做任何事情”?
所有这些操作都可以触发与未定义的指针进行评估的操作员相关的函数。 同样适用于铸造。
现在,如果你执行reintepret_cast,这可能是一个不同的故事,你可以相处,因为重新解释只是一点点重新解释,而不涉及(据我所知)任何方法调用。
出于同样的原因,您不会删除任何其他指针,然后尝试对其执行任何操作。
b / c这是指现在的地址,它是未定义的,你不知道可能在那里。
在一个multithreading程序中,当你delete
一个指针时,空闲空间可以被另一个线程分配,覆盖这个空间所使用的空间。 即使在一个单线程的程序中,除非你在return
之前非常小心你所调用的内容,否则你在delete this
之后做的任何事情都可以分配内存并覆盖以前被指向的内容。
在以debugging模式编译的Microsoft Visual C ++可执行文件中, delete
指针会导致其内存立即被0xCCtesting模式覆盖(未初始化的variables也会使用此模式进行初始化),以帮助识别悬挂的指针错误,如此类。
这让我想起当我在一个在线游戏中修正了一个错误,在这个游戏中,如果Fire的总数已经达到了一定的数字,Fire的构造函数就会删除最老的Fire。 被删除的火有时是父亲的火灾创造一个新的火b,悬挂指针错误! 只是因为运气这个bug以一种完全可预测的方式与内存分配algorithm相互作用(被删除的Fire总是被一个新的Fire以相同的方式覆盖),否则就会导致在线玩家之间的失步。 当重写游戏进行内存分配的方式时,我发现了这个错误。 由于它的可预测性,当我修复它的时候,我也能够实现它的行为模拟,以便与老的游戏客户兼容。