在g ++中删除此指针行为

时间:2010-01-15 13:01:00

标签: c++ gcc this-pointer

#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 ++如何处理这个?

7 个答案:

答案 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;也很危险。从那时起,该对象将无效,如果您尝试调用方法或访问成员,则您处于未定义的操作区域。