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;}
};
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。
除非是自己重写的不调用析构函数的operator delete。
#7
导致无限递归,而且还会堆栈溢出。
#9
对象如果要安全的自杀,得保证以下条件:
① this对象是必须用 new操作符分配(而不是用new[],也不是用placement new,也不是局部对象,也不是global对象)。
② delete this后,不能访问该对象任何的成员变量及虚函数(delete this回收的是数据,这包括对象的数据成员以及vtable,不包括函数代码)。
③ delete this后,不能再访问this指针。换句话说,你不能去检查它、将它和其他指针比较、和 NULL比较、打印它、转换它,以及其它的任何事情。
① this对象是必须用 new操作符分配(而不是用new[],也不是用placement new,也不是局部对象,也不是global对象)。
② delete this后,不能访问该对象任何的成员变量及虚函数(delete this回收的是数据,这包括对象的数据成员以及vtable,不包括函数代码)。
③ delete this后,不能再访问this指针。换句话说,你不能去检查它、将它和其他指针比较、和 NULL比较、打印它、转换它,以及其它的任何事情。
#10
这样的问题写个小程序一试不就知道了?
#11
在析构函数中已经不能再自杀了,因为它已经处于被杀的过程中。理论上讲,在析构中delete this必然造成循环删除自身
#12
构函数中调用delete this 不但不规范,并且不可取。delete this的时候会调用析构函数,而在析构函数中又调用delete this,死循环。
#13
我的理解是:
不管对象是否是动态申请的
都会出问题:
1:对于删除非指向动态申请空间的指针,行为是不可预知的
2:对于动态申请的对象, 在delete该对象的指针(其值与this指针的值相等)时,首先调用该对象所属类的析构函数,但是如果在析构函数里delete this指针后再delete 对象的指针,相当于同一动态内存区被析构两次。
不管对象是否是动态申请的
都会出问题:
1:对于删除非指向动态申请空间的指针,行为是不可预知的
2:对于动态申请的对象, 在delete该对象的指针(其值与this指针的值相等)时,首先调用该对象所属类的析构函数,但是如果在析构函数里delete this指针后再delete 对象的指针,相当于同一动态内存区被析构两次。
#14
不错,析构函数中如果delete this,必将形成死循环。
要自杀,也不要在析构函数中做。
这没有必要。
应该放在一个成员函数中做。
#15
vtable不是属于对象的,而是属于类的。对象里面的是vptr,指向它自身的类的vtable。delete操作只会将这个对象的vptr置0,而这个对象对应的类的vtable并不会被回收。(如果vtable都被回收了,那这个类的别的对象要怎么办?)
#16
delete 是与new配对使用的
#17
我记得在boost::shared_ptr还是Unordered中的源码就有delete this;
我有时间找找贴上来。。
我有时间找找贴上来。。
#18
这位仁兄别出来误导人了
#19
smart pointer delete的是它保存的指针
#20
shared_ptr
在sp_counted_base_nt.hpp
在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的例子大把了
不是在析构函数里面delete
在非析构函数里面delete的例子大把了
#22
对delete操作进行重载就可轻易解决这个问题。
#23
delete无非分两步:
第一步:调用~A()
第二步:释放内存。
我的重载不调用~A(),而是直接释放内存。就不会造成递归调用。
第一步:调用~A()
第二步:释放内存。
我的重载不调用~A(),而是直接释放内存。就不会造成递归调用。
#24
真无知
给你半个小时的时间去试,你试成功了没?
给你半个小时的时间去试,你试成功了没?
#25
我是来看楼上的签名的
#26
哈哈,我是菜鸟你满意了吧!
#27
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指向的内存,必然造成内存重复释放!!
#33
没有任何说类成员函数不能调用delete this,人家说的是“析构函数”不能调用这个!!!!
#34
非要跑出来出丑
菜也就算了,还不会动脑子,更要命的是还死要面
菜也就算了,还不会动脑子,更要命的是还死要面
#35
只有析构函数(可能构造函数也不行)内部调用这个,才会导致严重问题
#36
要注意使用方式。
你们把c++创建对象的方式看得太神秘了。
我完全可以避开c++方式,而模拟c++创建对象的过程。
说白了,最核心的就是申请内存,和初始值的问题。
class A{
public:
int a;
init(int b){a = b;}
};
A* p = (A*)malloc(sizeof(A));
p->init(9);
释放也是一样的。没有什么神奇的地方。
#37
yshuise 的意思是外部不调用delete,而是直接调用析构函数。
这样内存不会重复释放。
但当前类的类成员变量将无法释放内存,因为没有delete,导致类成员变量的析构函数得不到调用。即:内存泄露。
#38
说白了,最终还是申请内存问题,才是核心问题。
#39
你误会我的意思了(也怪我没有写清楚),因为当时我写这个的时候根本没有意识到“析构函数”中调用delete this的严重性,只是因为没有找到,所以没写进去。所以现在拿出来当笑话,调节调节气氛的
#40
yshuise 的意思是外部不调用delete,而是直接调用析构函数。
这样内存不会重复释放。
但当前类的类成员变量将无法释放内存,因为没有delete,导致类成员变量的析构函数得不到调用。即:内存泄露。
==================
对,是这个意思。
但是你提的第二个问题,仍然可以解决。当然还是得手动释放。
这样内存不会重复释放。
但当前类的类成员变量将无法释放内存,因为没有delete,导致类成员变量的析构函数得不到调用。即:内存泄露。
==================
对,是这个意思。
但是你提的第二个问题,仍然可以解决。当然还是得手动释放。
#41
是的,在析构函数里做其他类成员变量的析构函数调用。
#42
或者直接delete掉了事。
不过,这样是繁琐的。
不过,这样是繁琐的。
#43
在“析构函数”函数中使用delete this到可以用一个开关变量来控制,相反如何让类知道自己是不是被new出来的呢?
#44
那就重载new好了,通过一个全局容器记录申请到的内存地址,然后在new出来的类里查询this指针是否在这个容器里。我就是这样判断是否通过堆来创建对象的。
#45
你各种各样的建议的合理性和目的何在?为了让楼主在析构函数内delete?不考虑合理性的建议本身就不合理。
感觉你这确实在“玩笑”而不是在讨论问题,目的更多的是反驳CSDMAdmimistrator说你是菜鸟的问题。
感觉你这确实在“玩笑”而不是在讨论问题,目的更多的是反驳CSDMAdmimistrator说你是菜鸟的问题。
#46
要考虑合理性!!!就为了在析构中delete this,你做这个有意义么?
#47
为了让别人可以在析构中delete this,就建议人家不用delete,直接调用析构函数。实际上就是用一个错误的使用方法,去解决一个错误的不需要解决的问题。38楼说“说白了,最终还是申请内存问题,才是核心问题。”,这没错,但是解决这个核心问题的方法也是非常非常重要的。
而且,你这种建议也毫无实践可能性!如果你能控制每个使用这个类的人都来调用析构函数而不要delete,那没啥问题,但是哪个真正的项目能保证这个?
而且,你这种建议也毫无实践可能性!如果你能控制每个使用这个类的人都来调用析构函数而不要delete,那没啥问题,但是哪个真正的项目能保证这个?
#48
你好,析构函数中使用delete是C++的原意,就是用来释放类内存的;
首先你的例子中,
如果用A aa;
那么aa.p=aa;
不会出现任何无限循环,因为只是定义了一个指针,而没有开辟空间;
在析构函数中,使用了delete本身的内存空间,所以在使用这个类的时候就不需要用delete aa了,否则发生内存越界错误。直接调用,aa.~();就行了
首先会把aa的空间释放掉,也就没有了p;所以,后面的p=NULL要去掉,否则会发生内存错误。
首先你的例子中,
如果用A aa;
那么aa.p=aa;
不会出现任何无限循环,因为只是定义了一个指针,而没有开辟空间;
在析构函数中,使用了delete本身的内存空间,所以在使用这个类的时候就不需要用delete aa了,否则发生内存越界错误。直接调用,aa.~();就行了
首先会把aa的空间释放掉,也就没有了p;所以,后面的p=NULL要去掉,否则会发生内存错误。
#49
我的目的在于怎样去绕过它,而实现其功能。没有推广的意义。
#50
菜鸟会引入不少bug,但是都是显而易见的bug
而不懂装懂还死要脸的菜鸟就会为了解决一个bug引入无数的bug
#1
1.这会导致无限递归,但原因如何,并没有说明白。
============
我觉得这点可以排除。
============
我觉得这点可以排除。
#2
delete的要是new出来的内存吧
#3
代码还可以简洁的写成这样:
class A{
public:
A(){}
~A(){if (NULL != p) {delete this;}
};
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。
除非是自己重写的不调用析构函数的operator delete。
#7
导致无限递归,而且还会堆栈溢出。
#8
#9
对象如果要安全的自杀,得保证以下条件:
① this对象是必须用 new操作符分配(而不是用new[],也不是用placement new,也不是局部对象,也不是global对象)。
② delete this后,不能访问该对象任何的成员变量及虚函数(delete this回收的是数据,这包括对象的数据成员以及vtable,不包括函数代码)。
③ delete this后,不能再访问this指针。换句话说,你不能去检查它、将它和其他指针比较、和 NULL比较、打印它、转换它,以及其它的任何事情。
① this对象是必须用 new操作符分配(而不是用new[],也不是用placement new,也不是局部对象,也不是global对象)。
② delete this后,不能访问该对象任何的成员变量及虚函数(delete this回收的是数据,这包括对象的数据成员以及vtable,不包括函数代码)。
③ delete this后,不能再访问this指针。换句话说,你不能去检查它、将它和其他指针比较、和 NULL比较、打印它、转换它,以及其它的任何事情。
#10
这样的问题写个小程序一试不就知道了?
#11
在析构函数中已经不能再自杀了,因为它已经处于被杀的过程中。理论上讲,在析构中delete this必然造成循环删除自身
#12
构函数中调用delete this 不但不规范,并且不可取。delete this的时候会调用析构函数,而在析构函数中又调用delete this,死循环。
#13
我的理解是:
不管对象是否是动态申请的
都会出问题:
1:对于删除非指向动态申请空间的指针,行为是不可预知的
2:对于动态申请的对象, 在delete该对象的指针(其值与this指针的值相等)时,首先调用该对象所属类的析构函数,但是如果在析构函数里delete this指针后再delete 对象的指针,相当于同一动态内存区被析构两次。
不管对象是否是动态申请的
都会出问题:
1:对于删除非指向动态申请空间的指针,行为是不可预知的
2:对于动态申请的对象, 在delete该对象的指针(其值与this指针的值相等)时,首先调用该对象所属类的析构函数,但是如果在析构函数里delete this指针后再delete 对象的指针,相当于同一动态内存区被析构两次。
#14
不错,析构函数中如果delete this,必将形成死循环。
要自杀,也不要在析构函数中做。
这没有必要。
应该放在一个成员函数中做。
#15
vtable不是属于对象的,而是属于类的。对象里面的是vptr,指向它自身的类的vtable。delete操作只会将这个对象的vptr置0,而这个对象对应的类的vtable并不会被回收。(如果vtable都被回收了,那这个类的别的对象要怎么办?)
#16
delete 是与new配对使用的
#17
我记得在boost::shared_ptr还是Unordered中的源码就有delete this;
我有时间找找贴上来。。
我有时间找找贴上来。。
#18
这位仁兄别出来误导人了
#19
smart pointer delete的是它保存的指针
#20
shared_ptr
在sp_counted_base_nt.hpp
在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的例子大把了
不是在析构函数里面delete
在非析构函数里面delete的例子大把了
#22
对delete操作进行重载就可轻易解决这个问题。
#23
delete无非分两步:
第一步:调用~A()
第二步:释放内存。
我的重载不调用~A(),而是直接释放内存。就不会造成递归调用。
第一步:调用~A()
第二步:释放内存。
我的重载不调用~A(),而是直接释放内存。就不会造成递归调用。
#24
真无知
给你半个小时的时间去试,你试成功了没?
给你半个小时的时间去试,你试成功了没?
#25
我是来看楼上的签名的
#26
哈哈,我是菜鸟你满意了吧!
#27
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指向的内存,必然造成内存重复释放!!
#33
没有任何说类成员函数不能调用delete this,人家说的是“析构函数”不能调用这个!!!!
#34
非要跑出来出丑
菜也就算了,还不会动脑子,更要命的是还死要面
菜也就算了,还不会动脑子,更要命的是还死要面
#35
只有析构函数(可能构造函数也不行)内部调用这个,才会导致严重问题
#36
要注意使用方式。
你们把c++创建对象的方式看得太神秘了。
我完全可以避开c++方式,而模拟c++创建对象的过程。
说白了,最核心的就是申请内存,和初始值的问题。
class A{
public:
int a;
init(int b){a = b;}
};
A* p = (A*)malloc(sizeof(A));
p->init(9);
释放也是一样的。没有什么神奇的地方。
#37
yshuise 的意思是外部不调用delete,而是直接调用析构函数。
这样内存不会重复释放。
但当前类的类成员变量将无法释放内存,因为没有delete,导致类成员变量的析构函数得不到调用。即:内存泄露。
#38
说白了,最终还是申请内存问题,才是核心问题。
#39
你误会我的意思了(也怪我没有写清楚),因为当时我写这个的时候根本没有意识到“析构函数”中调用delete this的严重性,只是因为没有找到,所以没写进去。所以现在拿出来当笑话,调节调节气氛的
#40
yshuise 的意思是外部不调用delete,而是直接调用析构函数。
这样内存不会重复释放。
但当前类的类成员变量将无法释放内存,因为没有delete,导致类成员变量的析构函数得不到调用。即:内存泄露。
==================
对,是这个意思。
但是你提的第二个问题,仍然可以解决。当然还是得手动释放。
这样内存不会重复释放。
但当前类的类成员变量将无法释放内存,因为没有delete,导致类成员变量的析构函数得不到调用。即:内存泄露。
==================
对,是这个意思。
但是你提的第二个问题,仍然可以解决。当然还是得手动释放。
#41
是的,在析构函数里做其他类成员变量的析构函数调用。
#42
或者直接delete掉了事。
不过,这样是繁琐的。
不过,这样是繁琐的。
#43
在“析构函数”函数中使用delete this到可以用一个开关变量来控制,相反如何让类知道自己是不是被new出来的呢?
#44
那就重载new好了,通过一个全局容器记录申请到的内存地址,然后在new出来的类里查询this指针是否在这个容器里。我就是这样判断是否通过堆来创建对象的。
#45
你各种各样的建议的合理性和目的何在?为了让楼主在析构函数内delete?不考虑合理性的建议本身就不合理。
感觉你这确实在“玩笑”而不是在讨论问题,目的更多的是反驳CSDMAdmimistrator说你是菜鸟的问题。
感觉你这确实在“玩笑”而不是在讨论问题,目的更多的是反驳CSDMAdmimistrator说你是菜鸟的问题。
#46
要考虑合理性!!!就为了在析构中delete this,你做这个有意义么?
#47
为了让别人可以在析构中delete this,就建议人家不用delete,直接调用析构函数。实际上就是用一个错误的使用方法,去解决一个错误的不需要解决的问题。38楼说“说白了,最终还是申请内存问题,才是核心问题。”,这没错,但是解决这个核心问题的方法也是非常非常重要的。
而且,你这种建议也毫无实践可能性!如果你能控制每个使用这个类的人都来调用析构函数而不要delete,那没啥问题,但是哪个真正的项目能保证这个?
而且,你这种建议也毫无实践可能性!如果你能控制每个使用这个类的人都来调用析构函数而不要delete,那没啥问题,但是哪个真正的项目能保证这个?
#48
你好,析构函数中使用delete是C++的原意,就是用来释放类内存的;
首先你的例子中,
如果用A aa;
那么aa.p=aa;
不会出现任何无限循环,因为只是定义了一个指针,而没有开辟空间;
在析构函数中,使用了delete本身的内存空间,所以在使用这个类的时候就不需要用delete aa了,否则发生内存越界错误。直接调用,aa.~();就行了
首先会把aa的空间释放掉,也就没有了p;所以,后面的p=NULL要去掉,否则会发生内存错误。
首先你的例子中,
如果用A aa;
那么aa.p=aa;
不会出现任何无限循环,因为只是定义了一个指针,而没有开辟空间;
在析构函数中,使用了delete本身的内存空间,所以在使用这个类的时候就不需要用delete aa了,否则发生内存越界错误。直接调用,aa.~();就行了
首先会把aa的空间释放掉,也就没有了p;所以,后面的p=NULL要去掉,否则会发生内存错误。
#49
我的目的在于怎样去绕过它,而实现其功能。没有推广的意义。
#50
菜鸟会引入不少bug,但是都是显而易见的bug
而不懂装懂还死要脸的菜鸟就会为了解决一个bug引入无数的bug