本篇博客模擬實現一個String類,使用深拷貝的傳統與現代寫法。
深拷貝:重新開闢空間,將原來的空間拷貝過來,再把值複製過來,
此種方法兩個對象指向不同空間,析構時析構各自的數據塊,不會造成內存泄露問題。(稍後在代碼中解釋)
傳統寫法
思路:
使用傳統寫法:即老實人的寫法。
構造/拷貝構造/賦值運算符重載函數`先開闢空間再直接複製`
析構函數`如果_str!=NULL;釋放空間,並將_str置爲空,防止內存泄露`,所謂內存泄漏實際上丟失的是指針而非內存。
代碼實現:
#pragma once
//傳統寫法
class String
{
public:
//構造函數
String(char* str)
:_str(new char[strlen(str) + 1])//開闢空間
{
strcpy(_str, str);
}
//拷貝構造函數
//s2(s1)
String(const String &s)
{
this->_str = new char[strlen(s._str) + 1];
strcpy(_str, s._str);
}
//賦值運算符重載
//s2=s1
//s1=s1
String& operator=(const String& s)
{
if (this != &s)//避免自身賦值
{
delete[] _str;
_str = new char[strlen(s._str) + 1];
strcpy(_str, s._str);
}
return *this;
}
//打印字符串
const char* c_str()
{
return _str;
}
//析構函數
~String()
{
if (_str)
{
delete[] _str;
_str = NULL;
}
}
private:
char *_str;
};
//測試傳統寫法
void Test1()
{
String s1 = "Just Right";
String s2(s1);//調用拷貝構造函數,對象未存在
cout << "s1:"<<s1.c_str() << endl;
cout << "s2:" << s2.c_str() << endl;
String s3("hello world");
s1 = s3;//調用賦值運算符重載,對象已存在
cout << "s1:" << s1.c_str() << endl;
cout << "s3:" << s3.c_str() << endl;
}
結果爲:
現代寫法
思路:不開空間,藉助構造函數實現
//現代寫法
class String
{
public:
String(char *str)
:_str(new char[strlen(str)+1])
{
strcpy(_str, str);
}
//s2(s1)
String(const String& s)
:_str(NULL)
{
String tmp(s._str);//調用構造函數
swap(_str, tmp._str);
}
//s2=s1
String& operator=(const String& s)
{
if (this != &s)
{
String tmp(s._str);//調用構造函數
swap(_str, tmp._str);
}
return *this;
}
~String()
{
if (_str)
{
delete[] _str;
_str = NULL;
}
}
const char* c_str()
{
return _str;
}
private:
char *_str;
};
void Test2()
{
String s1 = "hello world";
String s2(s1);//調用拷貝構造函數,對象未存在
cout << "s1:" << s1.c_str() << endl;
cout << "s2:" << s2.c_str() << endl;
String s3("1234");
s1 = s3;//調用賦值運算符重載,對象已存在
cout << "s1:" << s1.c_str() << endl;
cout << "s3:" << s3.c_str() << endl;
}
分析:
結果:
由上圖發現s1與s2指向不同空間