嘿,我对一些C ++行为感到好奇,因为如果这种行为是一致的,我正在处理的代码将从简单性方面受益匪浅。基本上我的想法是针对我的对象A
中的特定函数来计算返回float
的复杂计算,但在返回float
之前,偶尔会调用delete this
。< / p>
1
这是我尝试验证的功能的一致代码示例。
#include <iostream>
#include <stdio.h>
#include <cstdlib>
using namespace std;
struct A
{
float test(float a) {delete this; return a;}
};
int main()
{
A *a = new A();
cout << a->test(1.f) << endl;
cout << "deleted?" << endl;
cout << a->test(1.f) << endl;
}
输出变为:
1.0
deleted?
*** Error in `./test': double free or corruption (fasttop): 0x0105d008 *** Aborted (core dumped)
我认为这意味着对象被正确删除了(内存中还剩下什么?一个不可召唤的A骨架?一个类型指针?一个空指针?),但我不确定我是否正确。如果是这样,这种行为是否一致(我的函数只会返回本机类型(浮动))
2
此外,我很好奇为什么这似乎不起作用:
struct A
{
float test(float a) {delete this; return a;}
};
int main()
{
A a;
cout << a.test(1.f) << endl;
}
这会编译但在返回任何内容之前会抛出以下错误。
*** Error in `./test': free(): invalid pointer: 0xbe9e4c64 *** Aborted (core dumped)
注意请不要回答一长串解释,说明为什么这是错误的编码/礼仪或其他什么,不在乎,我只是对可能性。
答案 0 :(得分:4)
成员函数调用delete this;
是安全的,如果您知道该对象是使用标量new
分配的,并且之后没有其他任何内容可以使用该对象。< / p>
在您的第一个示例中,在第一次调用a->test(1.f)
后,a
成为“悬空指针”。当您取消引用它以再次调用test
时,可以调用未定义的行为。
在第二个示例中,delete this;
语句是未定义的行为,因为该对象不是使用new
创建的。
答案 1 :(得分:1)
行为未定义,但在典型的现代实现中,访问解除分配的内存的实际“可能性”包括(但不限于):
delete
在运行时库级别(RTL)释放内存,但不会将其返回给操作系统。即未启用操作系统级别的内存保护,操作系统继续将内存视为已分配。但是,存储在释放的内存块中的内部RTL数据会破坏您的数据。结果:通过指针访问不会导致代码崩溃,但数据看起来毫无意义(破坏)
与1相同,但内部RTL数据不会与您的关键数据重叠。代码不会崩溃并继续工作“好像”一切都很“好”。
delete
向操作系统释放内存。启用了OS级别的内存保护。任何通过指针访问的尝试都会导致立即崩溃。
您的示例将按照第二种方案继续进行,即即使您释放内存后,存储在对象中的数据仍然保持不变。
您在代码中发现的崩溃发生是因为RTL检测到双free
次尝试(或尝试free
非动态内存,如第二个示例中所示),这除了指出你的问题。