在类中调用delete this问题

很多时候,一些定义在类内的变量的生命周期在类外并不是很好的掌控,这样就很容易造成内存泄漏得到问题

比如以下代码:

class Test
{
public:
    void foo();
private:
    char *p;
};

void Test::foo()
{
    p = new char[50];
}

int main()
{
    Test t1;
    t1.foo();
    return 0;
}

这是一个很典型的例子,new到的堆上空间并没有主动释放,即使程序结束也不会自动清除(不过现在操作系统比较高级,会强制返还程序运行前的内存....但这并不是我们不养成良好习惯的理由)。

那么这时候,在析构函数中加入delete[] p就是个很好的习惯。

那么,正题来了,如果我们在成员函数中delete自己会怎么样?

delete this

下面通过代码来看:

class Test
{
public:
    Test(int _x);
    void foo();
    void show();
    void show(int);
private:
    int x;
};

Test::Test(int _x) :x(_x)
{
}

void Test::show()
{
    cout << “x =” << x << endl;
}

void Test::show(int)
{
    cout << "this is show int"<< endl;
}

void Test::foo()
{
    delete this;
}

int main()
{
    Test *t1 = new Test(5);
    cout << "before" << endl;
    t1->show();
    t1->foo();
    cout << "after" << endl;
    //t1->show();
    t1->show(1);
    system("pause");
    return 0;
}

首先编译。结果是通过!证明在成员函数中调用delete this 并没有语法错误。

接下来运行:现在after后调用show(int)看delete this之后还能否调用成员函数。

结果如下图:

可以看到,delete this之后,该对象的成员函数还能调用。

那么,我们接下来就再次调用show()函数来看delete this 之后该对象中值释放还在。

结果如下图:

从结果来看,x已经变成随机值,看来对象内存空间的确是被释放了。

总结:

    在类的成员函数可以调用delete this,并且delete this之后还可以调用该对象的其他成员,但是有个前提:被调用的方法不涉及

这个对象的数据成员和虚函数。

     当一个类对象声明时,系统会为其分配内存空间。在类对象的内存空间中,只有数据成员和虚函数表指针,并不包含代码内

容,类的成员函数单独放在代码段中。在调用成员函数时,隐含传递一个this指针,让成员函数知道当前是哪个对象在调用它。

当 调用delete this时,类对象的内存空间被释放。在delete this之后进行的其他任何函数调用,只要不涉及到this指针的内容,都

能够正常运行。一旦涉及到this指针,如操作数据成员,调用虚函数等,就会出现不可预期的问题,即上面出现的随机值。

     为什么会出现这种情况?delete this之后不是释放了类对象的内存空间了么,那么这段内存应该已经还给系统,不再属于这个

进程。照这个逻辑来看,应该发生指针错误,无访问权限之类的令系统崩溃的问题才对啊?这个问题牵涉到操作系统的内存管理

策略。delete this释放了类对象的内存空间,但是内存空间却并不是马上被回收到系统中,可能是缓冲或者其他什么原因,导致

这段内存空间暂时并没有被系统收回。此时这段内存是可以访问的,你可以加上100,加上200,但是其中的值却是不确定的。当

你获取数据成员,可能得到的是一串很长的未初始化的随机数;访问虚函数表,指针无效的可能性非常高,造成系统崩溃。

    而若是下析构函数中呢?delete this会去调用本对象的析构函数,而析构函数中又调用delete this,形成无限递归,造成

堆栈溢出,系统崩溃。

上述总结参考了网上大神的一些言论,之前做的笔记,找不到是哪位了,,,不能标明,sorry

在单例模式,只有一个实例被创建并且被多个对象共享。当单例模式的实例在程序运行期间不再需要时,需要调用单例模式的析构函数来释放实例占用的内存。 在某些情况下,如果在单例模式的析构函数调用delete来释放实例占用的内存,可能会导致程序崩溃。这通常是由于单例模式的实例被其他对象依赖,而在析构函数delete实例之后,其他对象可能会尝试访问已经被释放的内存,导致undefined behavior。 以下是一个可能导致崩溃的单例模式的析构函数的示例代码: ``` class MyClass { public: static MyClass& getInstance() { static MyClass instance; return instance; } ~MyClass() { delete this; } private: MyClass() {} MyClass(const MyClass&) = delete; MyClass& operator=(const MyClass&) = delete; }; int main() { MyClass& myClass = MyClass::getInstance(); return 0; } ``` 在这个示例代码,单例模式的析构函数调用delete来释放实例占用的内存。但是,由于delete调用对象的析构函数,而在这个示例代码,MyClass没有显式定义析构函数,因此编译器会自动生成默认析构函数。这个默认析构函数什么也不做,因此delete实际上不会释放实例占用的内存。 当程序退出时,由于MyClass的析构函数并没有释放实例占用的内存,可能会导致内存泄漏。同时,由于MyClass的析构函数会调用delete,而delete调用析构函数,这可能会导致栈溢出或者其他undefined behavior。因此,建议在单例模式的析构函数不要调用delete,而是使用其他方法来释放实例占用的内存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值