今天我来介绍一下C++中的深浅拷贝问题。
一。浅拷贝
1.定义:也称位拷贝,编译器只是将对象中的值采用基本类型值复制的方式拷贝过来,如果对象中管理资源,最后就会导致
多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进行操作时,就会发生访问违规问题。
2.举例:
class String
{
public:
String(const char* str="") //构造函数
:_pstr(new char[strlen(str)+1]) //初始化列表
{
strcpy(_pstr,str); //拷贝
cout<<"string::string()"<<endl; //打印
}
~String() //析构函数
{
if(_pstr)
{
delete[] _pstr;
_pstr==NULL;
cout<<"string::~string()"<<endl;
}
}
private:
char* _pstr;
};
int main()
{
String s1("hello"); //调用构造函数创建对象。
String s2(s1); //调用拷贝构造函数创建对象。
return 0;
}
这个就是浅拷贝,当类的成员变量是指针时,因为没有自己写出拷贝构造函数,系统会自动生成,而此时系统只会拷贝内容,所以两个对象占用同一资源在同一块地址上,这样在释放时,会发生多次释放导致内存访问违规。所以说浅拷贝只是对类中的简单数据成员进行赋值,当类的成员变量存在指针成员时,就会出现问题,他只会拷贝指针,并不会改变地址。这就是浅拷贝。
二。深拷贝:
1.当成员为指针时,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针,这样就不会产生问题了。
2.举例:(1)传统法深拷贝:
class String
{
public:
String(const char* str="") //构造函数
{
if(str==NULL) //若为空初始化为空。
{
str="";
}
_pstr=new char[strlen(str)+1]; //否则进行拷贝。
strcpy(_pstr,str);
cout<<"string::string()"<<endl;
}
~String() //析构函数。
{
if(_pstr) //若不为空,进行销毁。
{
delete[] _pstr;
_pstr==NULL;
cout<<"string::~string()"<<endl;
}
}
String(const String& s) //拷贝构造函数。
:_pstr(new char[strlen(s._pstr)+1])
{
strcpy(_pstr,s._pstr);
}
String& operator=(const String& s) //赋值运算符重载函数
{
if(this!=&s) //当两者不相等时进行赋值。
{
char* t=new char[strlen(s._pstr)+1];
strcpy(t,s._pstr);
delete[] _pstr;
_pstr=t;
}
return *this;
}
private:
char* _pstr;
};
int main()
{
String s1("hello");
String s2(s1);
return 0;
}
(2)简洁版深拷贝:
class String
{
public:
String(const char* str="")
{
if(str==NULL)
{
str="";
}
_pstr=new char[strlen(_pstr)+1];
strcpy(_pstr,str);
}
~String()
{
if(_pstr)
{
delete[] _pstr;
_pstr==NULL;
}
}
String(const String& s)
:_pstr(NULL)
{
String t(s._pstr);
swap(_pstr,s._pstr);
}
String& operator=(const String& s)
{
String t(s);
swap(s._pstr,t._pstr);
return *this;
}
private:
char* _pstr;
};
int main()
{
String s1("hello");
String s2(s1);
return 0;
}
在深拷贝中,我们自己定义了拷贝构造函数,所以系统不会再用默认的函数,此时他就会开辟一个新的地址空间,所以此时两个对象指的地址不相同,就不会产生内存访问违规现象了。
3.所以总的来说:当类中有指针成员变量时,尽量自己写拷贝构造函数,这样就不会造成浅拷贝的问题了。
三。String类的增删改查:
//String类的各种操作:
class String
{
public:
String(const char* str="") //构造函数
{
_size=_capacity=strlen(str);
_str=new char[strlen(str)+1];
_capacity=_size;
strcpy(_str,str);
}
~String() //析构函数
{
if(_str)
{
delete[] _str;
_size=_capacity=0;
_str=NULL;
}
}
void Swap(String& s) //交换
{
swap(_str,s._str);
swap(_size,s._size);
swap(_capacity,s._capacity);
}
String(const String& s) //拷贝构造函数
:_str(NULL)
,_size(0)
,_capacity(0)
{
String t(s._str);
Swap(t);
}
String& operator=(String s) //赋值运算符重载
{
Swap(s);
return *this;
}
void expand(size_t n) //扩容函数
{
if(n>_capacity)
{
char* t=new char[n+1];
strcpy(t,_str);
delete[] _str;
_str=t;
_capacity=n;
}
}
void PushBack(char ch) //尾插字符
{
if(_size==_capacity)
{
expand(_capacity*2);
}
_str[_size]=ch;
_size++;
_str[_size]='\0';
}
void PushBack(const char* s) //尾插字符串
{
size_t len=strlen(s);
if(len>_capacity)
{
expand(_capacity*2);
}
strcpy(_str+_size,s);
_size=_size+len;
}
void PopBack() //尾删
{
if(_size==0)
{
return;
}
_size--;
_str[_size]='\0';
}
void PushFront(char ch) //头插字符
{
int i=0;
if(_size==_capacity)
{
expand(2*_capacity);
}
for(i=_size;i>=0;i--)
{
_str[i+1]=_str[i];
}
_str[0]=ch;
_size++;
}
void PushFront(const char* s) //头插字符串
{
char *p=_str;
size_t len=strlen(s);
int i=0;
if(_size+len>=_capacity)
{
expand(2*_capacity);
}
for(i=_size;i>=0;i--)
{
_str[i+len]=_str[i];
}
while(*s)
{
*p++=*s++;
}
_size+=len;
}
void PopFront() //头删
{
int i=0;
if(_size==0)
{
return;
}
if(_size==1)
{
_size--;
return;
}
for(i=0;i<_size;i++)
{
_str[i]=_str[i+1];
}
_size--;
}
void Insert(size_t pos, char ch) //任意位置插入字符
{
int i=0;
if(_size==_capacity)
{
expand(2*_capacity);
}
for(i=_size;i>(int)pos;i--)
{
_str[i+1]=_str[i];
}
_str[pos+1]=ch;
_size++;
}
void Insert(size_t pos,const char* s) //任意位置插入字符串
{
int i=0;
size_t len=strlen(s);
if(_size+len>_capacity)
{
expand(2*_capacity);
}
for(i=_size;i>pos;i--)
{
_str[i+len]=_str[i];
}
while(*s)
{
_str[++pos]=*s++;
}
_size+=len;
}
void Erase(size_t pos, size_t n = 1) //删除指定位置后的n个数
{
if(pos+n>_size-1)
{
_str[pos]='\0';
_size=pos;
}
else{
strcpy(_str+pos,_str+pos+n);
_size-=n;
}
}
size_t Find(char ch) //查询字符函数
{
size_t i=0;
for(i=0;i<_size;i++)
{
if(_str[i]==ch)
{
return i;
}
}
return 0;
}
void Replace(char ch1, char ch2) //用ch2替换ch1的函数
{
int i=0;
for(i=0;i<_size;i++)
{
if(_str[i]==ch1)
{
_str[i]=ch2;
}
}
}
bool operator<(const String& s) const //小于号重载
{
int i,j;
int a=_size;
int b=s._size;
for(i=0,j=0;i<a && j<b;i++,j++)
{
if(_str[i]>s._str[j])
{
return 0;
}
}
if(i==a && j<b)
{
return 1;
}
else{
return 0;
}
}
bool operator==(const String& str) const //等号重载
{
int i=0;
if(_size!=str._size)
{
return 0;
}
for(i=0;i<_size;i++)
{
if(_str[i]!=str._str[i])
{
return 0;
}
}
return 1;
}
bool operator>(const String& str) const //大于号重载
{
return (!(*this<str) && !(*this==str));
}
bool operator>=(const String& str) const //大于等于重载
{
return ((*this>str)&&(*this==str));
}
bool operator<=(const String& str) const //小于等于重载
{
return !(*this>str);
}
char& operator[](size_t pos) //[]的重载。
{
if(pos>_size)
{
return _str[_size];
}
return _str[pos];
}
const char * c_str()
{
return _str;
}
const size_t Size()
{
return _size;
}
private:
char *_str;
size_t _size;
size_t _capacity;
};