#include <stdio.h>
class Foo {
public:
Foo(char x);
Foo(char x, int y);
~Foo();
void abc();
void dev();
};
void Foo::dev()
{
printf("inside dev \n");
}
void Foo::abc()
{
printf("inside abc \n");
delete this;
dev();
}
Foo::Foo(char x)
{
printf("inside 1 argu const---------------");
}
Foo::~Foo()
{
printf("inside 1 argu dest---------------");
}
#include "test.h"
int main()
{
Foo *obj=new Foo('a');
printf("%u inside main\n", obj);
obj->abc();
return 0;
}
在查看程序的输出之后,似乎仍然调用“dev”函数,尽管在调用dev之前在函数abc中调用了“delete this”? gcc / g ++如何处理这个?
答案 0 :(得分:12)
对象可能仍然可用于未定义的时间。此外,delete
不会影响相关指针。
Delete
只调用对象实例上的析构函数。 Delete
将内存返回到池中,但未定义(与运行时相关)何时重用此内存(如果有的话)。在程序的剩余时间内,该对象可以很好地使用,但重点是:不要依赖它。
有一个不那么明显的陷阱需要注意:对象无法知道它是否是动态分配的。因此,如果对象是静态分配的调用,则对所述对象delete this
将证明是有问题的。但情况并非如此。
答案 1 :(得分:6)
删除只是释放内存(同样调用析构函数)。基本上你使用垃圾this
指针调用dev,它只能因为dev不是虚拟的而且它不会尝试访问任何成员变量,否则它可能会像使用任何其他无效指针一样访问违规。 / p>
答案 2 :(得分:2)
gcc / g ++如何处理这个问题?
从您的测试中可以看出它处理它。
虽然存在风险:例如,如果您修改dev
方法以访问Foo类的任何实例成员数据,那么您的行为(即在删除Foo实例后调用dev
方法)将是非法的,并且行为将是未定义的:实际行为将根据程序中其他地方发生的情况而变化,例如Foo实例占用的内存(以及Foo实例被删除时释放的内存)已由另一个线程重新分配。
如果dev
方法是虚方法,并且Foo是继承层次结构中的基类或子类,行为也会有所不同。
如果将dev
定义为静态方法会更好:
class Foo {
public:
Foo(char x);
Foo(char x, int y);
~Foo();
void abc();
static void dev();
};
如果你调用一个无法定义为静态的函数(因为它是虚拟的或因为它访问实例成员数据),那么做你正在做的事情是违法的。
答案 3 :(得分:1)
我希望此时调用dev();
,但它是未定义的行为,因为this
指针指向已被销毁的对象。你的电话似乎成功的原因是因为你正在变得幸运而且当你打电话this
时没有其他任何东西声称dev()
所指向的记忆,否则结果将是“有趣的” , 至少可以说。
答案 4 :(得分:1)
delete this
通常不会影响this指针本身,因此它仍可用于调用该函数。这种行为虽然未定义 - 它可能有效,但可能不行。通常,delete this
在C ++中是一个坏主意。使用它的唯一理由是在一些引用计数类中,并且有一些引用计数的方法,不需要使用它。
答案 5 :(得分:1)
Delete不会删除类的代码或静态变量,只删除实例变量。正如其他人所指出的那样,在删除对象指针后使用对象指针获得的行为是未定义的。
但问问自己(或者问一下stackoverflow ;-):如果没有类的实例存在,你可以调用类的静态成员函数吗? (答案是肯定的。)
如果dev()是静态的,那么这段代码就完全合法了。
答案 6 :(得分:0)
所有delete
都会调用析构函数,然后调用operator delete
(内置版本,如果您的类中没有覆盖)。它并不比free()
更聪明。没有什么可以阻止您使用已删除的对象。它确实无法正常工作。
调用delete this;
也很危险。从那时起,该对象将无效,如果您尝试调用方法或访问成员,则您处于未定义的操作区域。