string類中的傳統與現代實現方式

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.兩種相比較而言現代寫法充分的發揮了構造函數和析構函數的特點,合理高效的將現有資源進行了利用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章