在析构函数中调用delete this,会不会有问题?

时间:2022-09-11 13:24:56
前天就下段代码是否有问题,与几个同事进行了讨论,大家意见不一。

class A{
public:
  A(){p = this;}
  ~A(){if (NULL != p) {delete p;p = NULL;}}
A* p;
}

大家都认为上段代码肯定有问题,但问题具体在什么地方,意见不一。有以下几种观点:
1.这会导致无限递归,但原因如何,并没有说明白。
2.如果delete this 放在一个普通成员函数比如temp()中,或许就没问题了。
3.如果这是一个new产生的对象,也没有问题。

归纳起来,在以下两点上有争议:1.delete this是否放在析构函数中;2.这个对象是否是new 生成的。
情况不一样,结论也不一样。

不知道是否有高手能给以详细解答,我入社才一年多,实在想不通。。。
请高手指点迷津,理清思路。

162 个解决方案

#1


1.这会导致无限递归,但原因如何,并没有说明白。
============
我觉得这点可以排除。

#2


delete的要是new出来的内存吧

#3


代码还可以简洁的写成这样:
class A{ 
public: 
  A(){} 
  ~A(){if (NULL != p) {delete this;}
};

#4


是这样:
class A{ 
public: 
  A(){} 
  ~A(){delete this;} 
};

#5


参考COM,可以在确保对象是new出来的前提下在Release函数里调用delete this销毁对象

#6


默认的operator delete会调用析构函数吧,这样就会造成内部递归啊
除非是自己重写的不调用析构函数的operator delete。

#7


导致无限递归,而且还会堆栈溢出。

#9


对象如果要安全的自杀,得保证以下条件: 
① this对象是必须用 new操作符分配(而不是用new[],也不是用placement new,也不是局部对象,也不是global对象)。 
② delete this后,不能访问该对象任何的成员变量及虚函数(delete this回收的是数据,这包括对象的数据成员以及vtable,不包括函数代码)。 
③ delete this后,不能再访问this指针。换句话说,你不能去检查它、将它和其他指针比较、和 NULL比较、打印它、转换它,以及其它的任何事情。 

#10


这样的问题写个小程序一试不就知道了?

#11


在析构函数中已经不能再自杀了,因为它已经处于被杀的过程中。理论上讲,在析构中delete this必然造成循环删除自身
引用 9 楼 loaden 的回复:
对象如果要安全的自杀,得保证以下条件:
① this对象是必须用 new操作符分配(而不是用new[],也不是用placement new,也不是局部对象,也不是global对象)。
② delete this后,不能访问该对象任何的成员变量及虚函数(delete this回收的是数据,这包括对象的数据成员以及vtable,不包括函数代码)。
③ delete this后,不能再访问this指针。换句话说,你不能去检查它、将它和其他指针比较、和 NULL比较、打印它、转换它,以及其它的任何事情。

#12


构函数中调用delete this 不但不规范,并且不可取。delete this的时候会调用析构函数,而在析构函数中又调用delete this,死循环。

#13


我的理解是:
不管对象是否是动态申请的
都会出问题:
1:对于删除非指向动态申请空间的指针,行为是不可预知的
2:对于动态申请的对象, 在delete该对象的指针(其值与this指针的值相等)时,首先调用该对象所属类的析构函数,但是如果在析构函数里delete this指针后再delete 对象的指针,相当于同一动态内存区被析构两次。

#14


引用 11 楼 arong1234 的回复:
在析构函数中已经不能再自杀了,因为它已经处于被杀的过程中。理论上讲,在析构中delete this必然造成循环删除自身
引用 9 楼 loaden 的回复:
对象如果要安全的自杀,得保证以下条件:
① this对象是必须用 new操作符分配(而不是用new[],也不是用placement new,也不是局部对象,也不是global对象)。
② delete this后,不能访问该对象任何的成员变量及虚函数(delete this回收的是数据,这包括对象的数据成员以及vtable,不包括函数代码)。
③ delete this后,不能再访问this指针。换句话说,你不能去检查它、将它和其他指针比较、和 NULL比较、打印它、转换它,以及其它的任何事情。

不错,析构函数中如果delete this,必将形成死循环。
要自杀,也不要在析构函数中做。
这没有必要。
应该放在一个成员函数中做。

#15


引用 9 楼 loaden 的回复:
对象如果要安全的自杀,得保证以下条件:
 ① this对象是必须用 new操作符分配(而不是用new[],也不是用placement new,也不是局部对象,也不是global对象)。
 ② delete this后,不能访问该对象任何的成员变量及虚函数(delete this回收的是数据,这包括对象的数据成员以及vtable,不包括函数代码)。
 ③ delete this后,不能再访问this指针。换句话说,你不能去检查它、将它和其他指针比较、和 NULL比较、打印它、转换它,以及其它的任何事情。


vtable不是属于对象的,而是属于类的。对象里面的是vptr,指向它自身的类的vtable。delete操作只会将这个对象的vptr置0,而这个对象对应的类的vtable并不会被回收。(如果vtable都被回收了,那这个类的别的对象要怎么办?)

#16


delete 是与new配对使用的

#17


我记得在boost::shared_ptr还是Unordered中的源码就有delete this;

我有时间找找贴上来。。

#18


引用 17 楼 yshuise 的回复:
我记得在boost::shared_ptr还是Unordered中的源码就有delete this;

我有时间找找贴上来。。

这位仁兄别出来误导人了

#19


smart pointer delete的是它保存的指针

#20


shared_ptr
在sp_counted_base_nt.hpp

class sp_counted_base
{
private:

    sp_counted_base( sp_counted_base const & );
    sp_counted_base & operator= ( sp_counted_base const & );

    long use_count_;        // #shared
    long weak_count_;       // #weak + (#shared != 0)

public:

    sp_counted_base(): use_count_( 1 ), weak_count_( 1 )
    {
    }

    virtual ~sp_counted_base() // nothrow
    {
    }

    // dispose() is called when use_count_ drops to zero, to release
    // the resources managed by *this.

    virtual void dispose() = 0; // nothrow

    // destroy() is called when weak_count_ drops to zero.

    virtual void destroy() // nothrow
    {
        delete this;   //这个地方,大家看看
    }

    virtual void * get_deleter( sp_typeinfo const & ti ) = 0;

    void add_ref_copy()
    {
        ++use_count_;
    }

    bool add_ref_lock() // true on success
    {
        if( use_count_ == 0 ) return false;
        ++use_count_;
        return true;
    }

    void release() // nothrow
    {
        if( --use_count_ == 0 )
        {
            dispose();
            weak_release();
        }
    }

    void weak_add_ref() // nothrow
    {
        ++weak_count_;
    }

    void weak_release() // nothrow
    {
        if( --weak_count_ == 0 )
        {
            destroy();
        }
    }

    long use_count() const // nothrow
    {
        return use_count_;
    }
};

#21


看清楚了
不是在析构函数里面delete
在非析构函数里面delete的例子大把了

#22


引用 21 楼 csdmadmimistrator 的回复:
看清楚了
 不是在析构函数里面delete
 在非析构函数里面delete的例子大把了

对delete操作进行重载就可轻易解决这个问题。

#23


delete无非分两步:
第一步:调用~A()
第二步:释放内存。
我的重载不调用~A(),而是直接释放内存。就不会造成递归调用。

#24


真无知
给你半个小时的时间去试,你试成功了没?

#25


我是来看楼上的签名的

#26


引用 24 楼 csdmadmimistrator 的回复:
真无知
 给你半个小时的时间去试,你试成功了没?

哈哈,我是菜鸟你满意了吧!

#27


引用 23 楼 yshuise 的回复:
delete无非分两步:
第一步:调用~A()
第二步:释放内存。
我的重载不调用~A(),而是直接释放内存。就不会造成递归调用。


delete操作符是重载不了的……
能重载的是operator delete(不是 delete operator)……
换言之,只能重载第二步,第一步重载不了,也重载不了整个搭流程……

#28


由于delete会引发析构函数的调用,因此在析构函数中delete this会引递归的自身调用,将导致栈溢出……

#29



#include "stdafx.h"
#include <new>
class A
{
public:
void * operator new(size_t size){ 
return malloc(sizeof(A));
}
~A(){free( this);}
};

int _tmain(int argc, _TCHAR* argv[])
{
  
A* p = new A;
  p->~A();
return 0;
}

#30


我上面的意思就是要避免循环调用~A();

#31


看了LZ的问题,想起了我以前写的MFC代码,刚才翻出来了
void CMFCDlg::PostNcDestroy() 
{
UnregisterHotKey(m_hWnd,9999);
CDialog::PostNcDestroy();
delete this;//这里,貌似当时没找到(向导没生成)析构函数,不然,那时候肯定写进去试试
}

#32


你这样避免了死循环,但是造成了更严重问题,因为在调用完析构函数后,delete需要调用free之类的函数再释放内存。如果你再析构中释放this指向的内存,必然造成内存重复释放!!
引用 30 楼 yshuise 的回复:
我上面的意思就是要避免循环调用~A();

#33


没有任何说类成员函数不能调用delete this,人家说的是“析构函数”不能调用这个!!!!
引用 31 楼 pgplay 的回复:
看了LZ的问题,想起了我以前写的MFC代码,刚才翻出来了
C/C++ codevoid CMFCDlg::PostNcDestroy() 
{
    UnregisterHotKey(m_hWnd,9999);
    CDialog::PostNcDestroy();
    deletethis;//这里,貌似当时没找到(向导没生成)析构函数,不然,那时候肯定写进去试试}

#34


非要跑出来出丑
菜也就算了,还不会动脑子,更要命的是还死要面

#35


只有析构函数(可能构造函数也不行)内部调用这个,才会导致严重问题
引用 33 楼 arong1234 的回复:
没有任何说类成员函数不能调用delete this,人家说的是“析构函数”不能调用这个!!!!
引用 31 楼 pgplay 的回复:
看了LZ的问题,想起了我以前写的MFC代码,刚才翻出来了
C/C++ codevoid CMFCDlg::PostNcDestroy()
{
    UnregisterHotKey(m_hWnd,9999);
    CDialog::PostNcDestroy();
    deletethis;//这里,貌似当时没找到(向导没生成)析构函数,不然,那时候肯定写进去试试}

#36


引用 32 楼 arong1234 的回复:
你这样避免了死循环,但是造成了更严重问题,因为在调用完析构函数后,delete需要调用free之类的函数再释放内存。如果你再析构中释放this指向的内存,必然造成内存重复释放!!
引用 30 楼 yshuise 的回复:
 我上面的意思就是要避免循环调用~A();

要注意使用方式。
你们把c++创建对象的方式看得太神秘了。

我完全可以避开c++方式,而模拟c++创建对象的过程。
说白了,最核心的就是申请内存,和初始值的问题。


class A{
public:
int a;
init(int b){a = b;}
};

A* p = (A*)malloc(sizeof(A));
p->init(9);

释放也是一样的。没有什么神奇的地方。

#37


引用 32 楼 arong1234 的回复:
你这样避免了死循环,但是造成了更严重问题,因为在调用完析构函数后,delete需要调用free之类的函数再释放内存。如果你再析构中释放this指向的内存,必然造成内存重复释放!!
引用 30 楼 yshuise 的回复:
我上面的意思就是要避免循环调用~A();

yshuise 的意思是外部不调用delete,而是直接调用析构函数。
这样内存不会重复释放。
但当前类的类成员变量将无法释放内存,因为没有delete,导致类成员变量的析构函数得不到调用。即:内存泄露。

#38


说白了,最终还是申请内存问题,才是核心问题。

#39


引用 33 楼 arong1234 的回复:
没有任何说类成员函数不能调用delete this,人家说的是“析构函数”不能调用这个!!!!

你误会我的意思了(也怪我没有写清楚),因为当时我写这个的时候根本没有意识到“析构函数”中调用delete this的严重性,只是因为没有找到,所以没写进去。所以现在拿出来当笑话,调节调节气氛的

#40


yshuise 的意思是外部不调用delete,而是直接调用析构函数。 
这样内存不会重复释放。 
但当前类的类成员变量将无法释放内存,因为没有delete,导致类成员变量的析构函数得不到调用。即:内存泄露。
==================
对,是这个意思。
但是你提的第二个问题,仍然可以解决。当然还是得手动释放。

#41


引用 40 楼 yshuise 的回复:
yshuise 的意思是外部不调用delete,而是直接调用析构函数。
这样内存不会重复释放。
但当前类的类成员变量将无法释放内存,因为没有delete,导致类成员变量的析构函数得不到调用。即:内存泄露。
==================
对,是这个意思。
但是你提的第二个问题,仍然可以解决。当然还是得手动释放。

是的,在析构函数里做其他类成员变量的析构函数调用。

#42


或者直接delete掉了事。
不过,这样是繁琐的。

#43


在“析构函数”函数中使用delete this到可以用一个开关变量来控制,相反如何让类知道自己是不是被new出来的呢?

#44


引用 43 楼 pgplay 的回复:
在“析构函数”函数中使用delete this到可以用一个开关变量来控制,相反如何让类知道自己是不是被new出来的呢?

那就重载new好了,通过一个全局容器记录申请到的内存地址,然后在new出来的类里查询this指针是否在这个容器里。我就是这样判断是否通过堆来创建对象的。

#45


你各种各样的建议的合理性和目的何在?为了让楼主在析构函数内delete?不考虑合理性的建议本身就不合理。
感觉你这确实在“玩笑”而不是在讨论问题,目的更多的是反驳CSDMAdmimistrator说你是菜鸟的问题。
引用 39 楼 pgplay 的回复:
引用 33 楼 arong1234 的回复:
没有任何说类成员函数不能调用delete this,人家说的是“析构函数”不能调用这个!!!!

你误会我的意思了(也怪我没有写清楚),因为当时我写这个的时候根本没有意识到“析构函数”中调用delete this的严重性,只是因为没有找到,所以没写进去。所以现在拿出来当笑话,调节调节气氛的

#46


要考虑合理性!!!就为了在析构中delete this,你做这个有意义么?
引用 43 楼 pgplay 的回复:
在“析构函数”函数中使用delete this到可以用一个开关变量来控制,相反如何让类知道自己是不是被new出来的呢?

#47


为了让别人可以在析构中delete this,就建议人家不用delete,直接调用析构函数。实际上就是用一个错误的使用方法,去解决一个错误的不需要解决的问题。38楼说“说白了,最终还是申请内存问题,才是核心问题。”,这没错,但是解决这个核心问题的方法也是非常非常重要的。

而且,你这种建议也毫无实践可能性!如果你能控制每个使用这个类的人都来调用析构函数而不要delete,那没啥问题,但是哪个真正的项目能保证这个?

#48


你好,析构函数中使用delete是C++的原意,就是用来释放类内存的;
首先你的例子中,
如果用A aa;
那么aa.p=aa;
不会出现任何无限循环,因为只是定义了一个指针,而没有开辟空间;
在析构函数中,使用了delete本身的内存空间,所以在使用这个类的时候就不需要用delete aa了,否则发生内存越界错误。直接调用,aa.~();就行了
首先会把aa的空间释放掉,也就没有了p;所以,后面的p=NULL要去掉,否则会发生内存错误。

#49


我的目的在于怎样去绕过它,而实现其功能。没有推广的意义。

#50


引用 45 楼 arong1234 的回复:
你各种各样的建议的合理性和目的何在?为了让楼主在析构函数内delete?不考虑合理性的建议本身就不合理。
感觉你这确实在“玩笑”而不是在讨论问题,目的更多的是反驳CSDMAdmimistrator说你是菜鸟的问题。

菜鸟会引入不少bug,但是都是显而易见的bug
而不懂装懂还死要脸的菜鸟就会为了解决一个bug引入无数的bug

#1


1.这会导致无限递归,但原因如何,并没有说明白。
============
我觉得这点可以排除。

#2


delete的要是new出来的内存吧

#3


代码还可以简洁的写成这样:
class A{ 
public: 
  A(){} 
  ~A(){if (NULL != p) {delete this;}
};

#4


是这样:
class A{ 
public: 
  A(){} 
  ~A(){delete this;} 
};

#5


参考COM,可以在确保对象是new出来的前提下在Release函数里调用delete this销毁对象

#6


默认的operator delete会调用析构函数吧,这样就会造成内部递归啊
除非是自己重写的不调用析构函数的operator delete。

#7


导致无限递归,而且还会堆栈溢出。

#8


#9


对象如果要安全的自杀,得保证以下条件: 
① this对象是必须用 new操作符分配(而不是用new[],也不是用placement new,也不是局部对象,也不是global对象)。 
② delete this后,不能访问该对象任何的成员变量及虚函数(delete this回收的是数据,这包括对象的数据成员以及vtable,不包括函数代码)。 
③ delete this后,不能再访问this指针。换句话说,你不能去检查它、将它和其他指针比较、和 NULL比较、打印它、转换它,以及其它的任何事情。 

#10


这样的问题写个小程序一试不就知道了?

#11


在析构函数中已经不能再自杀了,因为它已经处于被杀的过程中。理论上讲,在析构中delete this必然造成循环删除自身
引用 9 楼 loaden 的回复:
对象如果要安全的自杀,得保证以下条件:
① this对象是必须用 new操作符分配(而不是用new[],也不是用placement new,也不是局部对象,也不是global对象)。
② delete this后,不能访问该对象任何的成员变量及虚函数(delete this回收的是数据,这包括对象的数据成员以及vtable,不包括函数代码)。
③ delete this后,不能再访问this指针。换句话说,你不能去检查它、将它和其他指针比较、和 NULL比较、打印它、转换它,以及其它的任何事情。

#12


构函数中调用delete this 不但不规范,并且不可取。delete this的时候会调用析构函数,而在析构函数中又调用delete this,死循环。

#13


我的理解是:
不管对象是否是动态申请的
都会出问题:
1:对于删除非指向动态申请空间的指针,行为是不可预知的
2:对于动态申请的对象, 在delete该对象的指针(其值与this指针的值相等)时,首先调用该对象所属类的析构函数,但是如果在析构函数里delete this指针后再delete 对象的指针,相当于同一动态内存区被析构两次。

#14


引用 11 楼 arong1234 的回复:
在析构函数中已经不能再自杀了,因为它已经处于被杀的过程中。理论上讲,在析构中delete this必然造成循环删除自身
引用 9 楼 loaden 的回复:
对象如果要安全的自杀,得保证以下条件:
① this对象是必须用 new操作符分配(而不是用new[],也不是用placement new,也不是局部对象,也不是global对象)。
② delete this后,不能访问该对象任何的成员变量及虚函数(delete this回收的是数据,这包括对象的数据成员以及vtable,不包括函数代码)。
③ delete this后,不能再访问this指针。换句话说,你不能去检查它、将它和其他指针比较、和 NULL比较、打印它、转换它,以及其它的任何事情。

不错,析构函数中如果delete this,必将形成死循环。
要自杀,也不要在析构函数中做。
这没有必要。
应该放在一个成员函数中做。

#15


引用 9 楼 loaden 的回复:
对象如果要安全的自杀,得保证以下条件:
 ① this对象是必须用 new操作符分配(而不是用new[],也不是用placement new,也不是局部对象,也不是global对象)。
 ② delete this后,不能访问该对象任何的成员变量及虚函数(delete this回收的是数据,这包括对象的数据成员以及vtable,不包括函数代码)。
 ③ delete this后,不能再访问this指针。换句话说,你不能去检查它、将它和其他指针比较、和 NULL比较、打印它、转换它,以及其它的任何事情。


vtable不是属于对象的,而是属于类的。对象里面的是vptr,指向它自身的类的vtable。delete操作只会将这个对象的vptr置0,而这个对象对应的类的vtable并不会被回收。(如果vtable都被回收了,那这个类的别的对象要怎么办?)

#16


delete 是与new配对使用的

#17


我记得在boost::shared_ptr还是Unordered中的源码就有delete this;

我有时间找找贴上来。。

#18


引用 17 楼 yshuise 的回复:
我记得在boost::shared_ptr还是Unordered中的源码就有delete this;

我有时间找找贴上来。。

这位仁兄别出来误导人了

#19


smart pointer delete的是它保存的指针

#20


shared_ptr
在sp_counted_base_nt.hpp

class sp_counted_base
{
private:

    sp_counted_base( sp_counted_base const & );
    sp_counted_base & operator= ( sp_counted_base const & );

    long use_count_;        // #shared
    long weak_count_;       // #weak + (#shared != 0)

public:

    sp_counted_base(): use_count_( 1 ), weak_count_( 1 )
    {
    }

    virtual ~sp_counted_base() // nothrow
    {
    }

    // dispose() is called when use_count_ drops to zero, to release
    // the resources managed by *this.

    virtual void dispose() = 0; // nothrow

    // destroy() is called when weak_count_ drops to zero.

    virtual void destroy() // nothrow
    {
        delete this;   //这个地方,大家看看
    }

    virtual void * get_deleter( sp_typeinfo const & ti ) = 0;

    void add_ref_copy()
    {
        ++use_count_;
    }

    bool add_ref_lock() // true on success
    {
        if( use_count_ == 0 ) return false;
        ++use_count_;
        return true;
    }

    void release() // nothrow
    {
        if( --use_count_ == 0 )
        {
            dispose();
            weak_release();
        }
    }

    void weak_add_ref() // nothrow
    {
        ++weak_count_;
    }

    void weak_release() // nothrow
    {
        if( --weak_count_ == 0 )
        {
            destroy();
        }
    }

    long use_count() const // nothrow
    {
        return use_count_;
    }
};

#21


看清楚了
不是在析构函数里面delete
在非析构函数里面delete的例子大把了

#22


引用 21 楼 csdmadmimistrator 的回复:
看清楚了
 不是在析构函数里面delete
 在非析构函数里面delete的例子大把了

对delete操作进行重载就可轻易解决这个问题。

#23


delete无非分两步:
第一步:调用~A()
第二步:释放内存。
我的重载不调用~A(),而是直接释放内存。就不会造成递归调用。

#24


真无知
给你半个小时的时间去试,你试成功了没?

#25


我是来看楼上的签名的

#26


引用 24 楼 csdmadmimistrator 的回复:
真无知
 给你半个小时的时间去试,你试成功了没?

哈哈,我是菜鸟你满意了吧!

#27


引用 23 楼 yshuise 的回复:
delete无非分两步:
第一步:调用~A()
第二步:释放内存。
我的重载不调用~A(),而是直接释放内存。就不会造成递归调用。


delete操作符是重载不了的……
能重载的是operator delete(不是 delete operator)……
换言之,只能重载第二步,第一步重载不了,也重载不了整个搭流程……

#28


由于delete会引发析构函数的调用,因此在析构函数中delete this会引递归的自身调用,将导致栈溢出……

#29



#include "stdafx.h"
#include <new>
class A
{
public:
void * operator new(size_t size){ 
return malloc(sizeof(A));
}
~A(){free( this);}
};

int _tmain(int argc, _TCHAR* argv[])
{
  
A* p = new A;
  p->~A();
return 0;
}

#30


我上面的意思就是要避免循环调用~A();

#31


看了LZ的问题,想起了我以前写的MFC代码,刚才翻出来了
void CMFCDlg::PostNcDestroy() 
{
UnregisterHotKey(m_hWnd,9999);
CDialog::PostNcDestroy();
delete this;//这里,貌似当时没找到(向导没生成)析构函数,不然,那时候肯定写进去试试
}

#32


你这样避免了死循环,但是造成了更严重问题,因为在调用完析构函数后,delete需要调用free之类的函数再释放内存。如果你再析构中释放this指向的内存,必然造成内存重复释放!!
引用 30 楼 yshuise 的回复:
我上面的意思就是要避免循环调用~A();

#33


没有任何说类成员函数不能调用delete this,人家说的是“析构函数”不能调用这个!!!!
引用 31 楼 pgplay 的回复:
看了LZ的问题,想起了我以前写的MFC代码,刚才翻出来了
C/C++ codevoid CMFCDlg::PostNcDestroy() 
{
    UnregisterHotKey(m_hWnd,9999);
    CDialog::PostNcDestroy();
    deletethis;//这里,貌似当时没找到(向导没生成)析构函数,不然,那时候肯定写进去试试}

#34


非要跑出来出丑
菜也就算了,还不会动脑子,更要命的是还死要面

#35


只有析构函数(可能构造函数也不行)内部调用这个,才会导致严重问题
引用 33 楼 arong1234 的回复:
没有任何说类成员函数不能调用delete this,人家说的是“析构函数”不能调用这个!!!!
引用 31 楼 pgplay 的回复:
看了LZ的问题,想起了我以前写的MFC代码,刚才翻出来了
C/C++ codevoid CMFCDlg::PostNcDestroy()
{
    UnregisterHotKey(m_hWnd,9999);
    CDialog::PostNcDestroy();
    deletethis;//这里,貌似当时没找到(向导没生成)析构函数,不然,那时候肯定写进去试试}

#36


引用 32 楼 arong1234 的回复:
你这样避免了死循环,但是造成了更严重问题,因为在调用完析构函数后,delete需要调用free之类的函数再释放内存。如果你再析构中释放this指向的内存,必然造成内存重复释放!!
引用 30 楼 yshuise 的回复:
 我上面的意思就是要避免循环调用~A();

要注意使用方式。
你们把c++创建对象的方式看得太神秘了。

我完全可以避开c++方式,而模拟c++创建对象的过程。
说白了,最核心的就是申请内存,和初始值的问题。


class A{
public:
int a;
init(int b){a = b;}
};

A* p = (A*)malloc(sizeof(A));
p->init(9);

释放也是一样的。没有什么神奇的地方。

#37


引用 32 楼 arong1234 的回复:
你这样避免了死循环,但是造成了更严重问题,因为在调用完析构函数后,delete需要调用free之类的函数再释放内存。如果你再析构中释放this指向的内存,必然造成内存重复释放!!
引用 30 楼 yshuise 的回复:
我上面的意思就是要避免循环调用~A();

yshuise 的意思是外部不调用delete,而是直接调用析构函数。
这样内存不会重复释放。
但当前类的类成员变量将无法释放内存,因为没有delete,导致类成员变量的析构函数得不到调用。即:内存泄露。

#38


说白了,最终还是申请内存问题,才是核心问题。

#39


引用 33 楼 arong1234 的回复:
没有任何说类成员函数不能调用delete this,人家说的是“析构函数”不能调用这个!!!!

你误会我的意思了(也怪我没有写清楚),因为当时我写这个的时候根本没有意识到“析构函数”中调用delete this的严重性,只是因为没有找到,所以没写进去。所以现在拿出来当笑话,调节调节气氛的

#40


yshuise 的意思是外部不调用delete,而是直接调用析构函数。 
这样内存不会重复释放。 
但当前类的类成员变量将无法释放内存,因为没有delete,导致类成员变量的析构函数得不到调用。即:内存泄露。
==================
对,是这个意思。
但是你提的第二个问题,仍然可以解决。当然还是得手动释放。

#41


引用 40 楼 yshuise 的回复:
yshuise 的意思是外部不调用delete,而是直接调用析构函数。
这样内存不会重复释放。
但当前类的类成员变量将无法释放内存,因为没有delete,导致类成员变量的析构函数得不到调用。即:内存泄露。
==================
对,是这个意思。
但是你提的第二个问题,仍然可以解决。当然还是得手动释放。

是的,在析构函数里做其他类成员变量的析构函数调用。

#42


或者直接delete掉了事。
不过,这样是繁琐的。

#43


在“析构函数”函数中使用delete this到可以用一个开关变量来控制,相反如何让类知道自己是不是被new出来的呢?

#44


引用 43 楼 pgplay 的回复:
在“析构函数”函数中使用delete this到可以用一个开关变量来控制,相反如何让类知道自己是不是被new出来的呢?

那就重载new好了,通过一个全局容器记录申请到的内存地址,然后在new出来的类里查询this指针是否在这个容器里。我就是这样判断是否通过堆来创建对象的。

#45


你各种各样的建议的合理性和目的何在?为了让楼主在析构函数内delete?不考虑合理性的建议本身就不合理。
感觉你这确实在“玩笑”而不是在讨论问题,目的更多的是反驳CSDMAdmimistrator说你是菜鸟的问题。
引用 39 楼 pgplay 的回复:
引用 33 楼 arong1234 的回复:
没有任何说类成员函数不能调用delete this,人家说的是“析构函数”不能调用这个!!!!

你误会我的意思了(也怪我没有写清楚),因为当时我写这个的时候根本没有意识到“析构函数”中调用delete this的严重性,只是因为没有找到,所以没写进去。所以现在拿出来当笑话,调节调节气氛的

#46


要考虑合理性!!!就为了在析构中delete this,你做这个有意义么?
引用 43 楼 pgplay 的回复:
在“析构函数”函数中使用delete this到可以用一个开关变量来控制,相反如何让类知道自己是不是被new出来的呢?

#47


为了让别人可以在析构中delete this,就建议人家不用delete,直接调用析构函数。实际上就是用一个错误的使用方法,去解决一个错误的不需要解决的问题。38楼说“说白了,最终还是申请内存问题,才是核心问题。”,这没错,但是解决这个核心问题的方法也是非常非常重要的。

而且,你这种建议也毫无实践可能性!如果你能控制每个使用这个类的人都来调用析构函数而不要delete,那没啥问题,但是哪个真正的项目能保证这个?

#48


你好,析构函数中使用delete是C++的原意,就是用来释放类内存的;
首先你的例子中,
如果用A aa;
那么aa.p=aa;
不会出现任何无限循环,因为只是定义了一个指针,而没有开辟空间;
在析构函数中,使用了delete本身的内存空间,所以在使用这个类的时候就不需要用delete aa了,否则发生内存越界错误。直接调用,aa.~();就行了
首先会把aa的空间释放掉,也就没有了p;所以,后面的p=NULL要去掉,否则会发生内存错误。

#49


我的目的在于怎样去绕过它,而实现其功能。没有推广的意义。

#50


引用 45 楼 arong1234 的回复:
你各种各样的建议的合理性和目的何在?为了让楼主在析构函数内delete?不考虑合理性的建议本身就不合理。
感觉你这确实在“玩笑”而不是在讨论问题,目的更多的是反驳CSDMAdmimistrator说你是菜鸟的问题。

菜鸟会引入不少bug,但是都是显而易见的bug
而不懂装懂还死要脸的菜鸟就会为了解决一个bug引入无数的bug