C++の深浅コピー及びString類基本操作
5810 ワード
今日はC++での深浅コピーについてご紹介します.
一.浅いコピー
1.定義:ビットコピーとも呼ばれ、コンパイラはオブジェクトの値を基本タイプの値でコピーするだけで、オブジェクトでリソースを管理すると、最後に複数のオブジェクトが同じリソースを共有し、1つのオブジェクトが破棄されるとそのリソースが解放されますが、他のオブジェクトはそのリソースが解放されたことを知りません.まだ有効だと思っています.したがって、リソースの操作を続行すると、アクセス違反の問題が発生します.
2.例:
これが浅いコピーです.クラスのメンバー変数がポインタの場合、コピー構造関数を自分で書かないため、システムは自動的に生成されます.この場合、システムはコンテンツをコピーするだけなので、2つのオブジェクトが同じリソースを同じアドレスに占有し、解放時にメモリアクセス違反が複数回発生します.したがって、浅いコピーはクラス内の単純なデータ・メンバーに値を割り当てるだけで、クラスのメンバー変数にポインタ・メンバーが存在する場合、問題が発生し、ポインタのみをコピーし、アドレスを変更しません.これが浅いコピーです.
二.深いコピー:
1.メンバーがポインタである場合、深いコピーはポインタだけでなく、ポインタが指す内容をコピーし、深いコピー後のポインタは2つの異なるアドレスを指すポインタであり、問題が発生しない.
2.例:(1)従来法の深いコピー:
(2)簡潔版の深いコピー:
深いコピーでは、コピー構造関数を定義しているので、デフォルトの関数は使用されません.この場合、新しいアドレス空間が開きます.したがって、2つのオブジェクトが指すアドレスが異なると、メモリアクセス違反は発生しません.
3.したがって、総じて、クラスにポインタメンバー変数がある場合は、できるだけ自分でコピー構造関数を書くようにして、浅いコピーの問題を引き起こすことはありません.
三.Stringクラスの追加削除:
一.浅いコピー
1.定義:ビットコピーとも呼ばれ、コンパイラはオブジェクトの値を基本タイプの値でコピーするだけで、オブジェクトでリソースを管理すると、最後に複数のオブジェクトが同じリソースを共有し、1つのオブジェクトが破棄されるとそのリソースが解放されますが、他のオブジェクトはそのリソースが解放されたことを知りません.まだ有効だと思っています.したがって、リソースの操作を続行すると、アクセス違反の問題が発生します.
2.例:
class String
{
public:
String(const char* str="") //
:_pstr(new char[strlen(str)+1]) //
{
strcpy(_pstr,str); //
cout<
これが浅いコピーです.クラスのメンバー変数がポインタの場合、コピー構造関数を自分で書かないため、システムは自動的に生成されます.この場合、システムはコンテンツをコピーするだけなので、2つのオブジェクトが同じリソースを同じアドレスに占有し、解放時にメモリアクセス違反が複数回発生します.したがって、浅いコピーはクラス内の単純なデータ・メンバーに値を割り当てるだけで、クラスのメンバー変数にポインタ・メンバーが存在する場合、問題が発生し、ポインタのみをコピーし、アドレスを変更しません.これが浅いコピーです.
二.深いコピー:
1.メンバーがポインタである場合、深いコピーはポインタだけでなく、ポインタが指す内容をコピーし、深いコピー後のポインタは2つの異なるアドレスを指すポインタであり、問題が発生しない.
2.例:(1)従来法の深いコピー:
class String
{
public:
String(const char* str="") //
{
if(str==NULL) // 。
{
str="";
}
_pstr=new char[strlen(str)+1]; // 。
strcpy(_pstr,str);
cout<
(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;
}
深いコピーでは、コピー構造関数を定義しているので、デフォルトの関数は使用されません.この場合、新しいアドレス空間が開きます.したがって、2つのオブジェクトが指すアドレスが異なると、メモリアクセス違反は発生しません.
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 _str="" _size--="" void="" insert="" pos="" char="" ch="" int="" i="0;" if="" expand="" for="">(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 if="" return="" i="" void="" replace="" ch1="" char="" ch2="" int="" for="" _str="" bool="" operator="" string="" s="" const="" a="_size;" b="s._size;" j="">s._str[j])
{
return 0;
}
}
if(i==a && j(const String& str) const //
{
return (!(*this=(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;
};