读书人

一个关于析构函数的有关问题,请高手帮

发布时间: 2012-08-16 12:02:15 作者: rapoo

一个关于析构函数的问题,请高手帮忙看看什么原因

C/C++ code
#include <iostream>#include <string>using namespace std;class Screen{};class smart_scrptr{friend class ScreenPtr;Screen *p;size_t load;smart_scrptr(Screen *sp):p(sp),load(1){}~smart_scrptr(){//    cout <<load<<endl;    delete p;//    cout <<load<<endl;}};class ScreenPtr{public://constructor     ScreenPtr(Screen *sp):ptr(new smart_scrptr(sp)){}//copyconstructorScreenPtr(const ScreenPtr& source):ptr(source.ptr){ptr->load++;}//operator controlScreenPtr& operator=(const ScreenPtr& source){    ptr=source.ptr;    source.ptr->load++;    return *this;}//destructor~ScreenPtr(){    if(--ptr->load==0)delete ptr;} private:    smart_scrptr *ptr;    };int main(){        Screen a;    Screen *pa=&a;    ScreenPtr sp=pa;    system("pause");    return 0;}


代码就是上面那些;

请注意我smart_scrptr类的析构函数:
~smart_scrptr(){
//cout <<load<<endl;
delete p;
//cout <<load<<endl;
}
问题就出现在这里,我直接编译以后,运行程序就会在程序析构的时候出错了 ,
然而当我把delete p;上下的两个//cout<<load<<endl;的注释去掉以后,程序却很奇怪的在析构的时候没有出错!
这其中的原因是什么请各位高手解释一下 ,
1>请帮忙解释一下为什么我这个程序在析构的时候会出错?
2>请帮忙解释一下为什么我把这两行注释去掉以后程序执行完毕在析构阶段不会产生异常

[解决办法]
探讨

应该不是那个问题吧!重载运算符不是已经对对象进行了深复制吗?

[解决办法]
怎么说呢?
因为Screen a本身在汗main结束后会马上自动调用析构函数销毁自己
然后到ScreenPtr sp=&a 调用析构析构函数,在delete ptr的过程又会调用
smart_scrptr的析构函数,删除p,因为p是指向&a的,然而a对象已经被销毁掉了,&a是一个野指针,
你在对野指针进行delete操作,当然会报错了.................

[解决办法]
smart_scrptr 的 析构函数要delete一个堆上的内存,但是你主函数里的screen不是堆上的,而是临时栈中的,所以当析构的时候就挂了,你改成Screen *pa = new Screen; 就ok了
[解决办法]
你能跟踪一下你的p指针吗?你看指向了哪里?

在smart_scrptr中你的p是个Screen类的指针,在ScreenPtr中你new的是一个smart_scrptr,把个局部的Screen指针传递给了p,然后你又delete p,肯定错误。

这么说吧,在main函数中,你传递的是个栈中的Screen地址,而用delete来释放,出现的错误。
很明显的是你new只出现了1次,而却出现了两次delete:

ScreenPtr(Screen *sp):ptr(new smart_scrptr(sp))

if(--ptr->load==0)delete ptr;

delete p;



[解决办法]
构造函数用了new,析构就用delete,当然相应的要自己实现复制构造函数和赋值函数
派生类没用new,析构就不要用delete,基类是否new和delete你不需要关心,反正派生类的构造和析构会自动去调用基类的构造和析构。

读书人网 >C++

热点推荐