为什么会内存溢出
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
using namespace std;
class String
{
private:
char* str;
int lne;
static int num;
public:
String( char* c );
~String(){cout<<"clear!\n";delete []str;}
friend ostream& operator<<(ostream& os,String &T);
};
String::String( char * c)
{
lne=strlen(c);
str=new char[lne+1];
strcpy(str,c);
}
ostream& operator<<(ostream& os,String& T)
{
os<<T.str<<"\t"<<endl;
return os;
}
void dispaly(String dl)
{
cout<<dl;
}
int main()
{
String l("hello,linux");
String H("hahahahahahahaahahah");
dispaly(l);
dispaly(H);
return 0;
}
[解决办法]
我也是菜鸟,希望我的信息能对你有所帮助,
我看了你的代码当dispaly(l)传参数的时候会调用拷贝构造函数,当dispaly(l)结束的时候,因为函数要退栈所以要调用析构函数,dispaly(H)也是一样的道理,因为你友元函数里使用的String类的引用所以当Dispaly()函数结束时已经调用了析构函数,当主函数推出时候又要调用析构函数,所以重复调用析构函数了。
[解决办法]
浅拷贝与深拷贝的问题,简单低说就是void String::dispaly(String dl)需要调用类的拷贝构造函数,但是你的String并没有显示定义该函数,所以编译器会给你自动生成一个拷贝构造函数,注意这里就出现问题了,编译器自动定义的拷贝构造函数实现的是浅拷贝,浅拷贝的大意是如果类中含有指针成员变量,那么浅拷贝只拷贝指针本身(动态内存空间地址),这样就使得一个地址有两个变量表示。
1.当void String::dispaly(String dl)函数退出时,析构副本对象,本来是释放副本的堆空间,但是副本和原本指向同一个地址堆空间,所以就相当于释放了原本堆空间。
2.当主函数退出时,析构原对象,由于原对象所指推空间已经被释放,这里再析构就存在同一个堆空间被释放2次,所以就错了。
3.假设你的代码中没有指针成员变量,你的上述代码是没有任何问题的。
建议:对于存在指针变量的类,尤其是指针所指空间在堆上,如果你需要使用类的拷贝构造函数,就必须显示定义它以实现深拷贝。
在你代码中添加一个函数:
String(String& c)
{
int len = strlen(c.str);
this->str = new char[len+1];
memcpy(this->str,c.str,len);
}