【C++】c++String類淺拷貝、深拷貝
阿新 • • 發佈:2019-02-10
在瞭解深拷貝以及寫時拷貝之前,我們先來了解什麼是淺拷貝,看下面程式碼:
class String
{
public:
String(char* ptr = "")
:_ptr(new char[strlen(ptr)+1])
{
if (_ptr != NULL)//空間開闢成功
{
strcpy(_ptr, ptr);
}
}
String(const String& s)
:_ptr(s._ptr)//直接賦值
{}
String& operator = (const String& s)
{
if (this != &s)
{
delete[] _ptr;
_ptr = s._ptr;//直接賦值
}
return *this;
}
~String()
{
if (_ptr)
{
delete[]_ptr;
}
}
private:
char* _ptr;
};
如下:s1、s2、s3是String類的三個物件,執行下列程式碼,目的是讓s1、s2、s3在各自的記憶體空間記憶體放著字串”sulijuan“,但卻事與願違。
String s1("sulijuan");
String s2(s1);
String s3;
s3 = s1;
可以通過除錯看到最後s1、s2、s3都指向了同一塊空間:
執行過程如下:
那麼可想而知,最後釋放物件的時候,理應呼叫三次解構函式來釋放三個物件,s3最先被釋放,當s3被釋放了以後,同時把s1、s2指向的空間一起釋放了,當再次呼叫解構函式想釋放s2時,程式崩潰了
~因為s2物件的_ptr指標指向的空間已經還給了作業系統,試圖去釋放一個不屬於你的空間必然崩潰~~~~~~~~
.為了解決淺拷貝的問題,引入了深拷貝。。。。。。。。
淺拷貝是多個物件指向了同一塊空間,導致最後釋放空間出現了問題;那麼深拷貝俗一點講就是讓每個物件對應一塊空間,各自管各自的空間,互不影響,最後釋放各自的空間。
程式碼如下:
class String
{
public:
String(char* ptr = "") //建構函式
:_ptr(new char[strlen(ptr)+1])
{
if (_ptr)
{
strcpy(_ptr, ptr);
}
}
String(const String& s)
:_ptr(new char[strlen(s._ptr)+1])//另外開闢空間
{
strcpy(_ptr, s._ptr);
}
String& operator= (const String& s)
{
if (this != &s)
{
delete[] _ptr;
_ptr = new char[strlen(s._ptr) + 1];//另外開闢空間
strcpy(_ptr, s._ptr);
}
return *this;
}
~String()
{
if (_ptr)
{
delete[] _ptr;
}
}
private:
char* _ptr;
};
再次執行下面程式碼:
String s1("sulijuan");
String s2(s1);
String s3;
s3 = s1;
除錯後可知各自開闢了一塊空間:
模擬庫內string類的一些字串基本操作實現如下:
#define EXPLAND_CAPICITY 5
class String
{
public:
String() //無參建構函式
:_size(0)
, _capicity(EXPLAND_CAPICITY)
, _str(new char[EXPLAND_CAPICITY])
{
*_str = '\0';
}
String(char* str) //建構函式過載
:_size(strlen(str)) //根據宣告先後順序進行初始化
, _capicity(_size+1)
, _str(new char[_capicity])
{
strcpy(_str,str);
}
String(const String& s) //深拷貝函式
:_size(s._size)
, _capicity(s._capicity)
, _str(new char[strlen(s._str)+1])
{
strcpy(_str,s._str);
}
~String() //解構函式
{
if (_str)
{
delete[] _str;
}
}
String& operator=(const String& s) //賦值運算子過載
{
if (this != &s)
{
delete[] _str;
_str = new char[strlen(s._str)+1];
strcpy(_str,s._str);
_size = s._size;
_capicity = s._capicity;
}
return *this;
}
void _CheckCapicity(int sCapicity)
{
if (_capicity - (_size + 1) < sCapicity)//檢查當前容量是否足以容下將要插入字串的長度
{
char* tmp = new char[_capicity + sCapicity];
_capicity += sCapicity;
strcpy(tmp, _str); //_size沒變
delete[] _str; //將原來空間釋放掉
_str = tmp; //_str指向新開闢的空間
}
}
void PushBack(char str)//尾插一個字元
{
_CheckCapicity(EXPLAND_CAPICITY);//如果當前所剩餘的容量小於5,則每次增加容量5,否則不增加
_str[_size++] = str; //將本來的'\0'改掉了
_str[_size] = '\0'; //新的結尾
}
void PushBack(char* str)//尾插字串
{
assert(str);
char* ptr = str;
int strLen = strlen(str);
_CheckCapicity(strLen);
while (strLen--)
{
_str[_size++] = *ptr++;
}
_str[_size] = '\0';
}
void PopBack() //尾刪字元
{
if (_size > 0)
{
_str[--_size] = '\0';
}
}
void Insert(int index,char str) //在下標為index處插入一個字元
{
assert(index < _size);
_CheckCapicity(EXPLAND_CAPICITY);
int i = _size;
for (; i>=index; --i)
{
_str[i+1] = _str[i];
}
_str[index] = str;
_size++;
}
void Insert(int index,char* str) ////在下標為index後面插入字串
{
assert(index < _size);
int strLen = strlen(str);
_CheckCapicity(strLen);
int i = _size;
for (; i > index; i--)
{
_str[i + strLen] = _str[i]; //把一個字元一次性挪到位
}
int j = index+1;
char* ptr = str;
while (strLen--)
{
_str[j++] = *ptr++; //迴圈一個一個插入字元
_size++;
}
}
int Find(char str)//查詢一個字元
{
int i = 0;
for (; i < _size; i++)
{
if (_str[i] == str)
{
return i;
}
}
return -1;
}
int Find(char* str)//查詢字串
{
assert(str);
int len = strlen(str);
int i, j, k;
for (i = 0; i < _size; i++)
{
k = i;
for (j = 0; j < len; j++,k++)
{
if (_str[k] != str[j])
{
break;
}
}
if (str[j] == '\0')
{
return i;
}
}
return -1;
}
/////////關係運算符過載函式////////////
bool operator== (const String& s)
{
char* ptr1 = _str;
char* ptr2 = s._str;
while (*ptr1 == *ptr2)
{
if (*ptr1 == '\0')
{
return true;
}
ptr1++;
ptr2++;
}
return false;
}
bool operator!= (const String& s)
{
return !(*this == s);
}
bool operator> (const String& s)
{
char* ptr1 = _str;
char* ptr2 = s._str;
while (*ptr1 == *ptr2)
{
if (*ptr1 == '\0')
{
return false;
}
ptr1++;
ptr2++;
}
if (*ptr1 > *ptr2)
{
return true;
}
else
{
return false;
}
}
bool operator>= (const String& s)
{
return (*this > s) || (*this == s);
}
bool operator< (const String& s)
{
return !(*this >= s);
}
bool operator<= (const String& s)
{
return !(*this > s);
}
//////////////////算術運算子過載函式////////////////
String operator+ (const String& s)
{
String tmp(*this);
tmp.PushBack(s._str);
return tmp;
}
String& operator += (const String& s)
{
*this = *this + s;
return *this;
}
friend ostream& operator<< (ostream& os, const String& s);//輸出<<運算子過載
private:
int _size; //字元個數
int _capicity; //字串容量
char* _str; //指向字串
};
ostream& operator<< (ostream& os,const String& s)
{
os << s._str<<endl;
return os;
}