类的构造与析构

来源:互联网 发布:尼格罗人种知乎 编辑:程序博客网 时间:2024/05/27 21:11

class T{//完成T=T+T的式子的问题public:int n[1000];char w;T* pre;T* next;//数据成员w帮助我们定位,n扩大占用资源以便观察是否存在内存泄漏T():pre(0),next(0){ w='0';::memset(n,0,1000);cout<<w<<":creat\n";}T(char name):pre(0),next(0){ w=name;cout<<w<<":creat\n";}~T(){cout<<w<<":delete\n";if(pre) {//pre->~T();delete pre;}if(next){// next->~T ();delete next;}//正确的}/*~T(){if(pre)pre->~T();if(next) next->~T ();}*/ //错误的析构函数T operator +(T a){ T*  t=new T('n');t->pre=this;t->next =&a;return *(t);}//重载运算 1T* operator +(T* a){ T*  t=new T('n');t->pre=this;t->next =a;//重载运算 2return (t);}T& operator +(T& a){ T*  t=new T('n');t->pre=this;t->next =&a;return *(t);}//重载运算 3};

我将以上面这个程序,探究类的传值和析构。

如果不熟悉类的特性,就很容易将上面这个类的析构函数写成注释中的,将重载运算符+写成 1 。

如果这样做会编译成功,但结果会是:

int _tmain(int argc, _TCHAR* argv[]){while(1){T a('a'),b('b'),*p;p=&(a+b);//会调用析构函数p->n[0]=2;//仍然可以访问}}本来设计的初衷是返回一个连接a,b的T类型的指针。然而却有着很大的问题:1.a,b,和new生成的n 的析构函数都被调用了。2.析构以后,其占用的资源没有被释放。问题 1:如果将重载运算符作修改重载运算 2赋值语句改为:p=a+&b;那么就不会调用析构函数。这里的差别就是函数返回T和T*,这里就想到了传值和传址。这里应该是由于传值时,自动产生的,也应自动销毁。于是就调用了析构函数。于是自然想到了解决方案:重载运算 3 (这里用了引用类型)经过测试,确实不会调用析构函数了。 然而我们不该忽略一点:在原来的函数里,函数返回的是拷贝到值,我们用&,取得的是这个拷贝的地址。拷贝会自动销毁,但我们利用这个指针却依然可以访问。难道其实它并没有被销毁?问题2:我用改进的方案取得地址,再调用析构函数,依然可以访问,资源也没有被释放。也就是析构函数失效了!其实是析构函数只是做销毁前的动作,并不会把资源消除也许是思维定势把,析构函数应该放置的是delete,就当T类的变量为一个局部变量。系统会自动的销毁它,而对于指针,系统不会去销毁它所对应的资源。故析构函数的作用就是手动的处理它们。经过测试,delete 类T时会调用~T,(新发现?还是编译器的问题,我用的是VS2010)所以需要将析构函数改成:~T(){cout<<w<<":delete\n";if(pre) {//pre->~T();delete pre;}if(next){// next->~T ();delete next;}}这样就可以了。






原创粉丝点击