string類中的傳統與現代實現方式
傳統寫法:
【原則】:
1.通過自己申請資源,拷貝內容
2.不會創建臨時對象
現在寫法:
【原則】:
1.自己不申請空間,不拷貝內容
2.通過調用構造函數(申請空間,拷貝內容)生成一個新的對象
3.直接獲取臨時對象的全部內容(通過交換指針完成),完成當前對象
的拷貝構造
4.不檢查是否爲自己給自己賦值因爲在賦值之前無空間的釋放操作
現代寫法中的圖示
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string.h>
#include<string>
using namespace std;
class String{
friend ostream& operator<<(ostream &_cout, const String &s);
//友元函數聲明
public:
String(char *sin="")
:_sin(new char[strlen(sin)+1] )
{
strcpy(_sin, sin);
}
//析構函數
~String()
{
if (_sin){
//判斷對象指針是否爲有效指針
delete[] _sin;//釋放堆上面的空間
_sin = nullptr;
}
}
//【拷貝構造】:傳統寫法
/*String(const String& s)
:_sin(new char[strlen(s._sin)+1])
{
strcpy(_sin, s._sin);
}*/
//現代寫法
String(const String& s)
:_sin(nullptr)
//若不置空的話,*this剛開始指向隨機值
//當其把內容交還給tmp._sin後,tmp._sin調用析構函數釋放的
//是隨機指針(程序奔潰)
{
String tmp(s._sin);
//調用構造函數生成同樣的一份資源,使得指針交換之後
//兩個指針指向的內容是一樣的
swap(_sin, tmp._sin);
}
//【賦值運算符重載】[傳統寫法]
/*String &operator=(const String&s){
if (this != &s){
//檢查是否爲自己給自己賦值
//要拷貝的字符串長度不一定和當前對象的字符串長度一致
//如果直接拷貝,空間不足的時候,會導致數據丟失
//所以直接釋放原來的空間,申請一個和當前要拷貝的字符串一樣大的空間
//_str至少有一個字節的空間,由構造函數保證的
delete[] _sin;
_sin = new char[strlen(s._sin) + 1];
strcpy(_sin, s._sin);
}
return *this;
}
*/
//【現代寫法】:賦值運算符重載
//傳入參數:傳值調用拷貝構造,不會調用賦值運算符重載
//不會引發賦值運算符無窮遞歸,通過調用拷貝構造完成拷貝
//傳值相當於在函數棧幀中生成一個臨時對象
//和拷貝構造相比,生成臨時對象的時機不同,
//拷貝構造:函數內部生成
//賦值:傳值的時候生成
String& operator=(String s){
String tmp(s);
swap(_sin,tmp._sin);
return *this;
}
char *c_str(){
return _sin;
}
private:
char* _sin;
};
ostream& operator<<(ostream &_cout, const String &s){
_cout << s._sin;
return _cout;
}
int main(){
String s="hello world";
cout << s << endl;
String s1(s);
cout << s1 << endl;
String s2;
s2 = s1;
//調用賦值運算符重載
cout << s2<<endl;
return 0;
}
【總結】
1.傳統寫法是按照正常的套路完成資源的拷貝和釋放
2.現代寫法是通過掉用構造函數和析構函數,以及交換對象指針的方式進行資源的拷貝和釋放.
3.兩種相比較而言現代寫法充分的發揮了構造函數和析構函數的特點,合理高效的將現有資源進行了利用。