c++关于析构函数释放内存的问题,求高手指教,急!!

时间:2022-09-30 00:00:27
我程序编译可以通过,运行过程中会出现一些致命性的错误,求高手指教,下面是我的代码:
#include<iostream>
using namespace std;

class Test
{
public:
int size;
int *p;
Test(int s)             //带参数的构造函数
{
size=s;
p=new int[size];
}
Test()                  //不带参数的构造函数
{
size=0;
p=new int[size];
}
Test clone(Test t)
{
Test result;
result.size=t.size;
result.p=t.p;
return result;
}
~Test()                    //析构函数
{
delete []p;            //这行注释掉程序就不会错
}
};

int main()
{
Test t1=Test(10);
Test t2=t1.clone(t1);
int i;
for(i=0;i!=t2.size;i++)
{
t2.p[i]=0;
}
return 0;
}
这段程序编译能通过没问题的,但是运行会出错,是内存不能访问的错误,如果我把析构函数中的“delete []p”这句话注释掉,程序运行就不会出错,所以我怀疑是不是不能这样用析构函数来释放内存,为了 防止内存泄漏,应该怎么样来释放内存,求大牛指点,谢谢。

21 个解决方案

#1


在析构前做 delete []p; 

#2


你只要学习一下 深拷贝 即可。直接指出程序的直接问题,不利于你学习。

#3


“直接指出程序的直接问题,不利于我学习”是什么意思,有点不太理解,还望多多指点

#4


clone函数,返回的是值,result只是一个临时变量,返回后会被析构,此时p已经被释放了,你的for循环里面再访问这个值肯定异常了。

#5


引用 3 楼 huxiaobing1989 的回复:
“直接指出程序的直接问题,不利于我学习”是什么意思,有点不太理解,还望多多指点

就是说,你需要主动修炼内功。

与甘草大神观点一致。楼主需要学习下c/c++基本知识。

clone函数看看吧,你只是指针一个复制而已。
指针指向内容没有复制,指针指向的区块是同一块。
然后析构了2次,Delete了2次。当然会出错。

#6


http://www.cnblogs.com/BlueTzar/articles/1223313.html

看这篇文章,和你情况类似。

#7


引用 2 楼 healer_kx 的回复:
你只要学习一下 深拷贝 即可。直接指出程序的直接问题,不利于你学习。

++

#8


甘草不是大神.是流氓.

#9


我觉得“PP[兔子党兔大常委]”说得挺有道理,我在调式过程中也发现析构了两次,大神们 能说具体点吗具体是那两次析构了

#10


引用 9 楼 huxiaobing1989 的回复:
我觉得“PP[兔子党兔大常委]”说得挺有道理,我在调式过程中也发现析构了两次,大神们 能说具体点吗具体是那两次析构了


看clone这个方法吧。
Test t是一个参数,你传入的是t1。但是由于你用默认的拷贝构造函数,所以此时t.p与t1.p指向同一个内存块。

然后有一个局部变量result,你又让result.p与t.p指向同一个内存块。

在Clone方法中有2个局部变量,参数t是一个,另一个是result。

当Clone方法返回时,需要销毁这两个局部变量,因为变量生命周期都结束了。
首先是t被销毁,调用一次析构函数,然后delete[] t.p;

然后是result被销毁,调用一次析构函数,delete[] result.p;

但是result.p, t.p都指向同一个内存块,都指向了t1.p指向的那块内存。
所以相当于t1.p Delete2次。就发生了Crash。

#11


不知道说清楚了没有。 c++关于析构函数释放内存的问题,求高手指教,急!!

#12


其实你也可以在析构的时候,加上一个判断

~Test() //析构函数
{
if (p != NULL)
  delete []p; //这行注释掉程序就不会错

p = NULL;
}

#13


10楼说的对,你要好好看懂这一块儿。

#14


clone函数看看吧,你只是指针一个复制而已。
这里你要NEW一下,然后MEMCPY把值COPY进去

#15


引用 12 楼 jxcr1984 的回复:
其实你也可以在析构的时候,加上一个判断

~Test() //析构函数
{
if (p != NULL)
  delete []p; //这行注释掉程序就不会错

p = NULL;
}

你这是不正确的,并没有指出LZ错误的地方啊,虽然没有报错

#16


要修改2处:

Test() //不带参数的构造函数
 {
   size=0;
   //p=new int[size];  不能这样写,此时 p 是有值的,它仍会指向一个地址,但这个地址你是没有分配内间的,如果后面要用到,一定会出错
   p=NULL;   //这里直接将p置为空
 }


 //Test clone(Test t)              这里不能直接用 Test t,否则这个 t是将t1复制一份出来,包括里面的*p,当退出clone时,会析构这个复制的t,但这个复制的t 与t1中的*p是指向同一个地方,此时,*p又会删除2次
 Test clone(Text &t)
 {
     //Test result;                 在退出clone时,result会被析构掉,所以不能这样,
     Test *result=new Test;         //而是应该new出一个对象来
     //result.size=t.size;
     //result.p=t.p;
     //return result;
     result->size=t.size;
     result->p=new int(t.size);     //新的Test中的p应该重新开辟新的内存
     CopyMemory(result->p,t.p,sizeof(int)*t.size);  //复制数据
     return *result;                //返回新的Test,注意,返回的对象是Text,Text是个类,所以即使是 return 你原来的 result,实质上也是一个指针,这里直接这样写就可以了,不用担心 *result=new Test;中的new,在t2析构时会被删除的
 }
 

#17


结帐,散分吧

#18


执行delete []p之前一定要判断p是否为NULL
if(p!=NULL)
{
delete []p;
p = NULL:
}

#19


size=0;
p=new int[size];

数组长度不能为0吧。

建议改成
size=0;
p=NULL;

然后在析构函数里
if(NULL!=p)
{
      delete []p;
}

否则直接delete悬垂指针会出大问题的

#20


result.p=t.p;

还有这行代码,当前一个对象被摧毁的时候所指向的内存会被释放。

这时复制对象的指针等同于指向了一个未分配地址导致悬垂指针。


建议用深拷贝。

#21


感谢各位大牛的解答,大家太给力了,可惜我的分不多,以后有机会再给各位慢慢加

#1


在析构前做 delete []p; 

#2


你只要学习一下 深拷贝 即可。直接指出程序的直接问题,不利于你学习。

#3


“直接指出程序的直接问题,不利于我学习”是什么意思,有点不太理解,还望多多指点

#4


clone函数,返回的是值,result只是一个临时变量,返回后会被析构,此时p已经被释放了,你的for循环里面再访问这个值肯定异常了。

#5


引用 3 楼 huxiaobing1989 的回复:
“直接指出程序的直接问题,不利于我学习”是什么意思,有点不太理解,还望多多指点

就是说,你需要主动修炼内功。

与甘草大神观点一致。楼主需要学习下c/c++基本知识。

clone函数看看吧,你只是指针一个复制而已。
指针指向内容没有复制,指针指向的区块是同一块。
然后析构了2次,Delete了2次。当然会出错。

#6


http://www.cnblogs.com/BlueTzar/articles/1223313.html

看这篇文章,和你情况类似。

#7


引用 2 楼 healer_kx 的回复:
你只要学习一下 深拷贝 即可。直接指出程序的直接问题,不利于你学习。

++

#8


甘草不是大神.是流氓.

#9


我觉得“PP[兔子党兔大常委]”说得挺有道理,我在调式过程中也发现析构了两次,大神们 能说具体点吗具体是那两次析构了

#10


引用 9 楼 huxiaobing1989 的回复:
我觉得“PP[兔子党兔大常委]”说得挺有道理,我在调式过程中也发现析构了两次,大神们 能说具体点吗具体是那两次析构了


看clone这个方法吧。
Test t是一个参数,你传入的是t1。但是由于你用默认的拷贝构造函数,所以此时t.p与t1.p指向同一个内存块。

然后有一个局部变量result,你又让result.p与t.p指向同一个内存块。

在Clone方法中有2个局部变量,参数t是一个,另一个是result。

当Clone方法返回时,需要销毁这两个局部变量,因为变量生命周期都结束了。
首先是t被销毁,调用一次析构函数,然后delete[] t.p;

然后是result被销毁,调用一次析构函数,delete[] result.p;

但是result.p, t.p都指向同一个内存块,都指向了t1.p指向的那块内存。
所以相当于t1.p Delete2次。就发生了Crash。

#11


不知道说清楚了没有。 c++关于析构函数释放内存的问题,求高手指教,急!!

#12


其实你也可以在析构的时候,加上一个判断

~Test() //析构函数
{
if (p != NULL)
  delete []p; //这行注释掉程序就不会错

p = NULL;
}

#13


10楼说的对,你要好好看懂这一块儿。

#14


clone函数看看吧,你只是指针一个复制而已。
这里你要NEW一下,然后MEMCPY把值COPY进去

#15


引用 12 楼 jxcr1984 的回复:
其实你也可以在析构的时候,加上一个判断

~Test() //析构函数
{
if (p != NULL)
  delete []p; //这行注释掉程序就不会错

p = NULL;
}

你这是不正确的,并没有指出LZ错误的地方啊,虽然没有报错

#16


要修改2处:

Test() //不带参数的构造函数
 {
   size=0;
   //p=new int[size];  不能这样写,此时 p 是有值的,它仍会指向一个地址,但这个地址你是没有分配内间的,如果后面要用到,一定会出错
   p=NULL;   //这里直接将p置为空
 }


 //Test clone(Test t)              这里不能直接用 Test t,否则这个 t是将t1复制一份出来,包括里面的*p,当退出clone时,会析构这个复制的t,但这个复制的t 与t1中的*p是指向同一个地方,此时,*p又会删除2次
 Test clone(Text &t)
 {
     //Test result;                 在退出clone时,result会被析构掉,所以不能这样,
     Test *result=new Test;         //而是应该new出一个对象来
     //result.size=t.size;
     //result.p=t.p;
     //return result;
     result->size=t.size;
     result->p=new int(t.size);     //新的Test中的p应该重新开辟新的内存
     CopyMemory(result->p,t.p,sizeof(int)*t.size);  //复制数据
     return *result;                //返回新的Test,注意,返回的对象是Text,Text是个类,所以即使是 return 你原来的 result,实质上也是一个指针,这里直接这样写就可以了,不用担心 *result=new Test;中的new,在t2析构时会被删除的
 }
 

#17


结帐,散分吧

#18


执行delete []p之前一定要判断p是否为NULL
if(p!=NULL)
{
delete []p;
p = NULL:
}

#19


size=0;
p=new int[size];

数组长度不能为0吧。

建议改成
size=0;
p=NULL;

然后在析构函数里
if(NULL!=p)
{
      delete []p;
}

否则直接delete悬垂指针会出大问题的

#20


result.p=t.p;

还有这行代码,当前一个对象被摧毁的时候所指向的内存会被释放。

这时复制对象的指针等同于指向了一个未分配地址导致悬垂指针。


建议用深拷贝。

#21


感谢各位大牛的解答,大家太给力了,可惜我的分不多,以后有机会再给各位慢慢加