Stringクラスの浅いコピーと深いコピー
2572 ワード
Stringクラスでは、オブジェクト間の相互コピーと付与が非常に重要な機能です.次に、この機能を実装してみましょう.
上記のバージョンのコピーについては、Stringクラスでchar*タイプのポインタを与えて与えられた文字列を指すことが明らかになります.ここでは、ポインタの単純な割り当て、つまり浅いコピーについてのみ、コピー構造関数を観察します.これでは、どのような問題が発生しますか.
明らかに、浅いコピー後、単純なポインタ間の付与のため、同じ空間を指す2つの異なるポインタがあり、この2つのポインタはそれぞれ2つの異なるオブジェクトから来ており、クラスのオブジェクトにとって、最終的にはプロファイル関数を呼び出してリソースをクリーンアップし、同じ空間が2回解放されるのではないでしょうか.これは明らかに崩壊するだろう.
上記の問題に対して、私たちは通常、コピーの時に新しいオブジェクトのために新しい空間を開きます.つまり、いわゆる深いコピーです.
この方法は主にコピー構造関数と付与演算子の再ロードを変更し,コピーを行う際に文字列に必要な空間を開くようにした.しかし、このバージョンに基づいて、私たちは少し変更することができます.
上記の代入演算子の再ロードには、次のような方法があります.
2つの方法は,パラメータを伝達する際に参照を伝達するか一時変数を伝達するかであり,自分に値を付与するか否かの判断に影響を与える.
深いコピーは問題を解決することができますが、浅いコピーは本当に問題を解決できませんか?
ここで,浅いコピーの問題は,複数のポインタを同じ空間に指向させ,リソースをクリーンアップする際に複数回の解放をもたらすことであると考えられる.もし私たちが事前にこの空間がどれだけの対象が使用されているかを知っていて、それから解放する前に判断して、この空間が他の人が使用しているかどうかを判断して、もしあれば、私たちはまずこの空間を解放しないで、あなたが最後にこの空間を使用していることを知っていて、それではこの空間は解放することができなくて、このように問題はありません.
これにより、次の2つの方法が使用できます.
1.オブジェクトにint*のポインタを構築し、4バイトの空間を指し、現在の使用量を保存します.pstrが指す空間のオブジェクト数.(カウントバージョン)
2.それ以外に、new[]の実装原理を真似して、この空間の先頭に4バイトを残して、現在この空間を使用しているオブジェクトの個数を保存することができます.(写実コピー)
class String
{
public:
String(const char* str) //
:_pstr(new char [strlen(str)+1])
{
strcpy(_pstr,str);
cout<
上記のバージョンのコピーについては、Stringクラスでchar*タイプのポインタを与えて与えられた文字列を指すことが明らかになります.ここでは、ポインタの単純な割り当て、つまり浅いコピーについてのみ、コピー構造関数を観察します.これでは、どのような問題が発生しますか.
明らかに、浅いコピー後、単純なポインタ間の付与のため、同じ空間を指す2つの異なるポインタがあり、この2つのポインタはそれぞれ2つの異なるオブジェクトから来ており、クラスのオブジェクトにとって、最終的にはプロファイル関数を呼び出してリソースをクリーンアップし、同じ空間が2回解放されるのではないでしょうか.これは明らかに崩壊するだろう.
上記の問題に対して、私たちは通常、コピーの時に新しいオブジェクトのために新しい空間を開きます.つまり、いわゆる深いコピーです.
class String
{
public:
String(const char* str="\0") //
{
if(str==NULL)
{
_pstr=new char[1];
*_pstr='\0';
}
else
{
_pstr=new char[strlen(str)+1];
strcpy(_pstr,str);
}
cout<
この方法は主にコピー構造関数と付与演算子の再ロードを変更し,コピーを行う際に文字列に必要な空間を開くようにした.しかし、このバージョンに基づいて、私たちは少し変更することができます.
class String
{
public:
String(const char* str="\0") //
{
if(str==NULL)
{
_pstr=new char[1];
*_pstr='\0';
}
else
{
_pstr=new char[strlen(str)+1];
strcpy(_pstr,str);
}
cout<
上記の代入演算子の再ロードには、次のような方法があります.
String& operator=(String& str)
{
if(this!=&str)
{
String tmp(str);
std::swap(_pstr,tmp._pstr);
}
return *this;
}
2つの方法は,パラメータを伝達する際に参照を伝達するか一時変数を伝達するかであり,自分に値を付与するか否かの判断に影響を与える.
深いコピーは問題を解決することができますが、浅いコピーは本当に問題を解決できませんか?
ここで,浅いコピーの問題は,複数のポインタを同じ空間に指向させ,リソースをクリーンアップする際に複数回の解放をもたらすことであると考えられる.もし私たちが事前にこの空間がどれだけの対象が使用されているかを知っていて、それから解放する前に判断して、この空間が他の人が使用しているかどうかを判断して、もしあれば、私たちはまずこの空間を解放しないで、あなたが最後にこの空間を使用していることを知っていて、それではこの空間は解放することができなくて、このように問題はありません.
これにより、次の2つの方法が使用できます.
1.オブジェクトにint*のポインタを構築し、4バイトの空間を指し、現在の使用量を保存します.pstrが指す空間のオブジェクト数.(カウントバージョン)
class String
{
public:
String(const char* str="\0")
{
if(str==NULL)
{
_pstr=new char[1];
*_pstr='\0';
}
else
{
_pstr=new char[strlen(str)+1];
strcpy(_pstr,str);
}
count=new int[1];
*count=1;
cout<
2.それ以外に、new[]の実装原理を真似して、この空間の先頭に4バイトを残して、現在この空間を使用しているオブジェクトの個数を保存することができます.(写実コピー)
class String
{
public:
String(const char* str="\0")
{
if(str==NULL)
{
_pstr=new char[5];
_pstr+=4;
GetCount(_pstr)=1;
*_pstr='\0';
}
else
{
_pstr=new char[strlen(str)+5];
_pstr+=4;
GetCount(_pstr)=1;
strcpy(_pstr,str);
}
cout<