#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
class RefCountedBase {
protected:
~RefCountedBase() {
printf("~RefCountedBase\n");
}
RefCountedBase() : ref_count_(0) {
printf("RefCountedBase:%x\n", this);
}
void AddRef() {
++ref_count_;
}
bool Release() {
if (--ref_count_ == 0) {
return true;
}
return false;
}
private:
int ref_count_;
DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
};
template <class T>
class RefCounted : public RefCountedBase {
public:
~RefCounted() {
printf("~RefCounted\n");
}
RefCounted() {
printf("RefCounted:%x\n", this);
}
void AddRef() {
RefCountedBase::AddRef();
}
void Release() {
if (RefCountedBase::Release()) {
delete static_cast<T*>(this);
}
}
private:
DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);
};
template <class T>
class scoped_refptr {
public:
scoped_refptr() : ptr_(NULL) {
printf("scoped_refptr:%x\n", this);
}
scoped_refptr(T* p) : ptr_(p) {
if (ptr_)
ptr_->AddRef();
}
scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
if (ptr_)
ptr_->AddRef();
}
~scoped_refptr() {
if (ptr_)
ptr_->Release();
}
T* get() const { return ptr_; }
operator T*() const { return ptr_; }
T* operator->() const { return ptr_; }
scoped_refptr<T>& operator=(T* p) {
// AddRef first so that self assignment should work
if (p)
p->AddRef();
if (ptr_ )
ptr_ ->Release();
ptr_ = p;
return *this;
}
scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
return *this = r.ptr_;
}
void swap(T** pp) {
T* p = ptr_;
ptr_ = *pp;
*pp = p;
}
void swap(scoped_refptr<T>& r) {
swap(&r.ptr_);
}
private:
T* ptr_;
};
class A : public RefCounted<A>
{
public:
A(){
printf("A:%x\n", this);
}
~A(){
printf("~A\n");
}
void Afun()
{
if (this == NULL)
{
printf("NULL:%x\n", this);
return;
}
printf("afun:%x\n", this);
}
private:
DISALLOW_COPY_AND_ASSIGN(A);
};
void f()
{
scoped_refptr<A> a = new A();
a->Afun();
a = NULL;
a->Afun();
}
int _tmain(int argc, _TCHAR* argv[])
{
f();
return 0;
}
注意看f()函数中第二次调用a->Afun();应该出错才对,可是结果却是调用成功,没有任何异常,请教各位高手这是为什么呢?
23 个解决方案
#1
看样子,你的scoped_refptr类重载了赋值操作,当a = NULL;时,内部的指针做了一定的处理..没仔细看,下班走人了
#2
a->Afun();//你输出结果是不是NULL:0呢。如果是,那么就是正常的啊
#3
对一个指向NULL的指针进行delete不会有什么不良影响
#4
a = NULL;
//这里的时候,a已经析构delete掉了~~
a->Afun();//此时a->返回的是0;
然后0->Afun();
而Afun中没有读写内存操作,是可以运行通过而不崩溃的~~
//这里的时候,a已经析构delete掉了~~
a->Afun();//此时a->返回的是0;
然后0->Afun();
而Afun中没有读写内存操作,是可以运行通过而不崩溃的~~
#5
但是不建议这么用,如果你的A类里面有指针,而且Afun()中有使用这些指针进行读写的话,就很容易出问题。
#6
不是这样的吧?我不用模板类,定义一个普通的类这样操作后,调用的函数中仍然是个输出语句,但是程序一定会崩的,所以您的解释不成立
#7
按理来讲对象都析构掉了,还怎么可能调用一个不存在的方法呢?我在不用模板的情况话定义一个类,然后进行这样的操作结果一定是崩溃
#8
您好像有点文不对题啊?一个空指针正常来讲您觉得能调用任何方法吗?况且所调用的方法也已经被析构掉了
#9
你试过了?
#10
学习!!!
#11
给你个例子:
struct Test{
void fun(){
cout<<"Test"<<endl;
}
};
int main()
{
((Test*)0)->fun();
system("pause");
return 0;
}
struct Test{
void fun(){
cout<<"Test"<<endl;
}
};
int main()
{
((Test*)0)->fun();
system("pause");
return 0;
}
#12
没自己写过这么长的智能指针……,还好代码看得懂,说下我的理解。
4楼的解释应该差不多。
a->Afun();
a里边的ptr是NULL,所以:NULL->Afun();
别忘了,这里的Afun()不是虚函数,所以编译器在生成指令的时候是直接生成对函数Afun()的调用。它在生成指令的时候不知道ptr会等于NULL,因为是成员函数,所以还会传递一个this指针,这个this指针就是ptr的值,是NULL(也就是0)。所以才会有NULL:0的输出。
就像4楼说的,在成员函数里边没有用到成员变量、或者虚函数(这两个都需要用到this指针来寻址)。那就不会崩溃。
至于你6楼所说的,没代码,就不知道了。
4楼的解释应该差不多。
a->Afun();
a里边的ptr是NULL,所以:NULL->Afun();
别忘了,这里的Afun()不是虚函数,所以编译器在生成指令的时候是直接生成对函数Afun()的调用。它在生成指令的时候不知道ptr会等于NULL,因为是成员函数,所以还会传递一个this指针,这个this指针就是ptr的值,是NULL(也就是0)。所以才会有NULL:0的输出。
就像4楼说的,在成员函数里边没有用到成员变量、或者虚函数(这两个都需要用到this指针来寻址)。那就不会崩溃。
至于你6楼所说的,没代码,就不知道了。
#13
当然试过啦,就是因为一般来说都会崩溃,而这里没有崩溃我才发帖请教的
#14
没看懂,呵呵
#15
编译下我11楼给的代码
#16
访问空指针的后果为“未定义”,崩溃只是其中一种可能。你现在真学到的就是第二种可能。
其实不存在“一般XXXX”这种说法,你必须修正自己的错误认识。
其实不存在“一般XXXX”这种说法,你必须修正自己的错误认识。
#17
楼主:
实际上,当你写a=NULL; a->Afun();时,表面上的确是0->Afun(),但别忘了编译后的成员函数的样子:
void A_Afun(A* a); (函数名是乱编的,看编译器怎么进行名称重整而定)
所以0->Afun()实际上就是A_Afun(this); (this为NULL)
而你的代码有保护检查,如下:
void Afun()
{
if (this == NULL)
{
printf("NULL:%x\n", this);
return;
}
printf("afun:%x\n", this);
}
所以不会崩溃。(即使没有,你也没有通过NULL来读写所指内存,因而没问题,反之必崩!)
实际上,当你写a=NULL; a->Afun();时,表面上的确是0->Afun(),但别忘了编译后的成员函数的样子:
void A_Afun(A* a); (函数名是乱编的,看编译器怎么进行名称重整而定)
所以0->Afun()实际上就是A_Afun(this); (this为NULL)
而你的代码有保护检查,如下:
void Afun()
{
if (this == NULL)
{
printf("NULL:%x\n", this);
return;
}
printf("afun:%x\n", this);
}
所以不会崩溃。(即使没有,你也没有通过NULL来读写所指内存,因而没问题,反之必崩!)
#18
我觉得您分析的很有道理,但是还有一点我一直想不通,难道说一个类被析构了,它的成员函数还存在于内存中吗?我的成员函数又不是静态的,我的理解是它应该随着这个类一起销毁掉了才对呀,还请赐教
#19
其一,将a=NULL并不会析构a;
其二,类的成员函数的定义是(函数体的代码)与类的某个对象的生命周期不是一回事,无论你产生多少个对象,其成员函数的二进制代码也只有一份拷贝。其实与静态成员函数代码是一样的,只不过静态成员函数内没有this指针。
其二,类的成员函数的定义是(函数体的代码)与类的某个对象的生命周期不是一回事,无论你产生多少个对象,其成员函数的二进制代码也只有一份拷贝。其实与静态成员函数代码是一样的,只不过静态成员函数内没有this指针。
#20
⊙﹏⊙b汗。我12楼的回复被忽略了。
看你18楼的回复,觉得你对对象和类的关系搞不清,先学习基础再说吧。
如果,了解了编译器是怎么处理对非虚成员函数的调用的、了解了类跟对象的关系,就不会有那么多的疑问。
看你18楼的回复,觉得你对对象和类的关系搞不清,先学习基础再说吧。
如果,了解了编译器是怎么处理对非虚成员函数的调用的、了解了类跟对象的关系,就不会有那么多的疑问。
#21
delete 只是给内存至乐个标志 只要不访问里面的数据成员 就没得问题
#22
不好意思,不是忽略您的回复,的确如您所说,我这边基础不太好,对象和类有点混乱了,今天我用同样的代码跑了一次我前面说的必崩的代码,居然没有崩,看来确实如16楼所说的那样,崩溃只是一种可能,最后感谢您的回复,小弟受教了
#23
您可能没有仔细看代码,这个是智能指针,在赋空值时其对象同时也被析构了
您说的第二点我没有意见,现在基本搞清楚原因了,在这里谢谢您啦
#1
看样子,你的scoped_refptr类重载了赋值操作,当a = NULL;时,内部的指针做了一定的处理..没仔细看,下班走人了
#2
a->Afun();//你输出结果是不是NULL:0呢。如果是,那么就是正常的啊
#3
对一个指向NULL的指针进行delete不会有什么不良影响
#4
a = NULL;
//这里的时候,a已经析构delete掉了~~
a->Afun();//此时a->返回的是0;
然后0->Afun();
而Afun中没有读写内存操作,是可以运行通过而不崩溃的~~
//这里的时候,a已经析构delete掉了~~
a->Afun();//此时a->返回的是0;
然后0->Afun();
而Afun中没有读写内存操作,是可以运行通过而不崩溃的~~
#5
但是不建议这么用,如果你的A类里面有指针,而且Afun()中有使用这些指针进行读写的话,就很容易出问题。
#6
不是这样的吧?我不用模板类,定义一个普通的类这样操作后,调用的函数中仍然是个输出语句,但是程序一定会崩的,所以您的解释不成立
#7
按理来讲对象都析构掉了,还怎么可能调用一个不存在的方法呢?我在不用模板的情况话定义一个类,然后进行这样的操作结果一定是崩溃
#8
您好像有点文不对题啊?一个空指针正常来讲您觉得能调用任何方法吗?况且所调用的方法也已经被析构掉了
#9
你试过了?
#10
学习!!!
#11
给你个例子:
struct Test{
void fun(){
cout<<"Test"<<endl;
}
};
int main()
{
((Test*)0)->fun();
system("pause");
return 0;
}
struct Test{
void fun(){
cout<<"Test"<<endl;
}
};
int main()
{
((Test*)0)->fun();
system("pause");
return 0;
}
#12
没自己写过这么长的智能指针……,还好代码看得懂,说下我的理解。
4楼的解释应该差不多。
a->Afun();
a里边的ptr是NULL,所以:NULL->Afun();
别忘了,这里的Afun()不是虚函数,所以编译器在生成指令的时候是直接生成对函数Afun()的调用。它在生成指令的时候不知道ptr会等于NULL,因为是成员函数,所以还会传递一个this指针,这个this指针就是ptr的值,是NULL(也就是0)。所以才会有NULL:0的输出。
就像4楼说的,在成员函数里边没有用到成员变量、或者虚函数(这两个都需要用到this指针来寻址)。那就不会崩溃。
至于你6楼所说的,没代码,就不知道了。
4楼的解释应该差不多。
a->Afun();
a里边的ptr是NULL,所以:NULL->Afun();
别忘了,这里的Afun()不是虚函数,所以编译器在生成指令的时候是直接生成对函数Afun()的调用。它在生成指令的时候不知道ptr会等于NULL,因为是成员函数,所以还会传递一个this指针,这个this指针就是ptr的值,是NULL(也就是0)。所以才会有NULL:0的输出。
就像4楼说的,在成员函数里边没有用到成员变量、或者虚函数(这两个都需要用到this指针来寻址)。那就不会崩溃。
至于你6楼所说的,没代码,就不知道了。
#13
当然试过啦,就是因为一般来说都会崩溃,而这里没有崩溃我才发帖请教的
#14
没看懂,呵呵
#15
编译下我11楼给的代码
#16
访问空指针的后果为“未定义”,崩溃只是其中一种可能。你现在真学到的就是第二种可能。
其实不存在“一般XXXX”这种说法,你必须修正自己的错误认识。
其实不存在“一般XXXX”这种说法,你必须修正自己的错误认识。
#17
楼主:
实际上,当你写a=NULL; a->Afun();时,表面上的确是0->Afun(),但别忘了编译后的成员函数的样子:
void A_Afun(A* a); (函数名是乱编的,看编译器怎么进行名称重整而定)
所以0->Afun()实际上就是A_Afun(this); (this为NULL)
而你的代码有保护检查,如下:
void Afun()
{
if (this == NULL)
{
printf("NULL:%x\n", this);
return;
}
printf("afun:%x\n", this);
}
所以不会崩溃。(即使没有,你也没有通过NULL来读写所指内存,因而没问题,反之必崩!)
实际上,当你写a=NULL; a->Afun();时,表面上的确是0->Afun(),但别忘了编译后的成员函数的样子:
void A_Afun(A* a); (函数名是乱编的,看编译器怎么进行名称重整而定)
所以0->Afun()实际上就是A_Afun(this); (this为NULL)
而你的代码有保护检查,如下:
void Afun()
{
if (this == NULL)
{
printf("NULL:%x\n", this);
return;
}
printf("afun:%x\n", this);
}
所以不会崩溃。(即使没有,你也没有通过NULL来读写所指内存,因而没问题,反之必崩!)
#18
我觉得您分析的很有道理,但是还有一点我一直想不通,难道说一个类被析构了,它的成员函数还存在于内存中吗?我的成员函数又不是静态的,我的理解是它应该随着这个类一起销毁掉了才对呀,还请赐教
#19
其一,将a=NULL并不会析构a;
其二,类的成员函数的定义是(函数体的代码)与类的某个对象的生命周期不是一回事,无论你产生多少个对象,其成员函数的二进制代码也只有一份拷贝。其实与静态成员函数代码是一样的,只不过静态成员函数内没有this指针。
其二,类的成员函数的定义是(函数体的代码)与类的某个对象的生命周期不是一回事,无论你产生多少个对象,其成员函数的二进制代码也只有一份拷贝。其实与静态成员函数代码是一样的,只不过静态成员函数内没有this指针。
#20
⊙﹏⊙b汗。我12楼的回复被忽略了。
看你18楼的回复,觉得你对对象和类的关系搞不清,先学习基础再说吧。
如果,了解了编译器是怎么处理对非虚成员函数的调用的、了解了类跟对象的关系,就不会有那么多的疑问。
看你18楼的回复,觉得你对对象和类的关系搞不清,先学习基础再说吧。
如果,了解了编译器是怎么处理对非虚成员函数的调用的、了解了类跟对象的关系,就不会有那么多的疑问。
#21
delete 只是给内存至乐个标志 只要不访问里面的数据成员 就没得问题
#22
不好意思,不是忽略您的回复,的确如您所说,我这边基础不太好,对象和类有点混乱了,今天我用同样的代码跑了一次我前面说的必崩的代码,居然没有崩,看来确实如16楼所说的那样,崩溃只是一种可能,最后感谢您的回复,小弟受教了
#23
您可能没有仔细看代码,这个是智能指针,在赋空值时其对象同时也被析构了
您说的第二点我没有意见,现在基本搞清楚原因了,在这里谢谢您啦