#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
就是说,你需要主动修炼内功。
与甘草大神观点一致。楼主需要学习下c/c++基本知识。
clone函数看看吧,你只是指针一个复制而已。
指针指向内容没有复制,指针指向的区块是同一块。
然后析构了2次,Delete了2次。当然会出错。
#6
http://www.cnblogs.com/BlueTzar/articles/1223313.html
看这篇文章,和你情况类似。
看这篇文章,和你情况类似。
#7
++
#8
甘草不是大神.是流氓.
#9
我觉得“PP[兔子党兔大常委]”说得挺有道理,我在调式过程中也发现析构了两次,大神们 能说具体点吗具体是那两次析构了
#10
看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
不知道说清楚了没有。
#12
其实你也可以在析构的时候,加上一个判断
~Test() //析构函数
{
if (p != NULL)
delete []p; //这行注释掉程序就不会错
p = NULL;
}
~Test() //析构函数
{
if (p != NULL)
delete []p; //这行注释掉程序就不会错
p = NULL;
}
#13
10楼说的对,你要好好看懂这一块儿。
#14
clone函数看看吧,你只是指针一个复制而已。
这里你要NEW一下,然后MEMCPY把值COPY进去
这里你要NEW一下,然后MEMCPY把值COPY进去
#15
你这是不正确的,并没有指出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:
}
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悬垂指针会出大问题的
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
就是说,你需要主动修炼内功。
与甘草大神观点一致。楼主需要学习下c/c++基本知识。
clone函数看看吧,你只是指针一个复制而已。
指针指向内容没有复制,指针指向的区块是同一块。
然后析构了2次,Delete了2次。当然会出错。
#6
http://www.cnblogs.com/BlueTzar/articles/1223313.html
看这篇文章,和你情况类似。
看这篇文章,和你情况类似。
#7
++
#8
甘草不是大神.是流氓.
#9
我觉得“PP[兔子党兔大常委]”说得挺有道理,我在调式过程中也发现析构了两次,大神们 能说具体点吗具体是那两次析构了
#10
看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
不知道说清楚了没有。
#12
其实你也可以在析构的时候,加上一个判断
~Test() //析构函数
{
if (p != NULL)
delete []p; //这行注释掉程序就不会错
p = NULL;
}
~Test() //析构函数
{
if (p != NULL)
delete []p; //这行注释掉程序就不会错
p = NULL;
}
#13
10楼说的对,你要好好看懂这一块儿。
#14
clone函数看看吧,你只是指针一个复制而已。
这里你要NEW一下,然后MEMCPY把值COPY进去
这里你要NEW一下,然后MEMCPY把值COPY进去
#15
你这是不正确的,并没有指出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:
}
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悬垂指针会出大问题的
p=new int[size];
数组长度不能为0吧。
建议改成
size=0;
p=NULL;
然后在析构函数里
if(NULL!=p)
{
delete []p;
}
否则直接delete悬垂指针会出大问题的
#20
result.p=t.p;
还有这行代码,当前一个对象被摧毁的时候所指向的内存会被释放。
这时复制对象的指针等同于指向了一个未分配地址导致悬垂指针。
建议用深拷贝。
还有这行代码,当前一个对象被摧毁的时候所指向的内存会被释放。
这时复制对象的指针等同于指向了一个未分配地址导致悬垂指针。
建议用深拷贝。
#21
感谢各位大牛的解答,大家太给力了,可惜我的分不多,以后有机会再给各位慢慢加