日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++深淺拷貝及簡易string類實現方式_C 語言

作者:安河橋畔 ? 更新時間: 2023-04-06 編程語言

三種拷貝方式

淺拷貝

對于自定義的string類,如果不顯式定義拷貝構造函數,編譯器會默認生成拷貝構造函數,此時的拷貝方式是淺拷貝,兩個對象會公用一塊兒內存,析構時同一空間被釋放兩次,會導致程序崩潰。

賦值運算符重載也會產生同樣的問題,同時,由于被賦值對象原來有空間,淺拷貝還會導致舊的空間無法找到,造成內存泄漏。

深拷貝

類中設計到資源的管理,拷貝構造函數、賦值運算符重載以及析構函數都要顯示給出,按照深拷貝的方式。

深拷貝的方式讓每個對象都獨立擁有一份資源,不會造成多次釋放導致程序崩潰的問題。

寫時拷貝

寫時拷貝是通過淺拷貝+引用計數的方式來實現的,引用計數是用來記錄資源的被引用的次數,

可以將這種寫時拷貝的機制想象成“拖延癥”,只有當不得不進行拷貝時,才會開辟新空間進行拷貝

VS與GCC中的拷貝方式

Windows VS2022

VS中采用的是深拷貝的方式

Linux GCC

GCC編譯器采用的是寫時拷貝的方式

簡易string類

簡易string類主要實現四個功能,即構造函數、拷貝構造函數、析構函數、賦值運算符重載,主要考察深淺拷貝

實現簡易string類有兩種代碼風格,一種傳統版寫法,代碼復用性第,可讀性較好;另一種稱為現代版寫法,代碼復用性高,但是較難理解。

傳統版寫法的string類

構造函數

步驟:

  • 判斷是否為空指針,string類不允許nullptr構造對象
  • 申請新空間
  • 將字符串中的值拷貝到申請的空間
string(const char* str = "")
{
	if (nullptr == str)
	{
		assert(false);
		return;
	}
	//+1是因為有'\0',strcpy會將源字符串中的'\0'拷貝到目標空間
	_str = new char[strlen(str) + 1];
	strcpy(_str, str);
}

拷貝構造函數

步驟:

  • 開辟空間
  • 用源對象的_str給當前對象的_str賦值
string(const string& s)
	:_str(new char[strlen(s._str) + 1])
{
	strcpy(_str, s._str);
}

賦值運算符重載

步驟:

  • 判斷是否自己給自己賦值
  • 開辟新空間
  • 拷貝元素
  • 刪除舊空間
string& operator=(const string& s)
{
	//避免自己給自己賦值
	if (this != &s)
	{
		char* temp = new char[strlen(s._str) + 1];
		strcpy(temp, s._str);
		delete[] _str;
		_str = temp;
	}
	return *this;
}

另一種寫法

這種寫法不用定義臨時變量,代碼相對簡潔一點,但是如果new申請空間失敗,舊的空間也無法找到。

析構函數

步驟:

  • 釋放空間
  • 將指針置為空
~string()
{
?? ?if (_str)
?? ?{
?? ??? ?delete[]_str;
?? ??? ?_str = nullptr;
?? ?}
}

?

現代版寫法string類

構造函數

string(const char* str = "")
{
	if (str == nullptr)
	{
		assert(false);
	}
	_str = new char[strlen(str) + 1];
	strcpy(_str, str);
}

拷貝構造函數

拷貝構造函數中利用構造函數,實現了代碼的復用

步驟:

  • 在初始化列表中將_str置為空
  • 定義一個臨時的string類對象,指向要拷貝的對象相同位置
  • 交換臨時對象與當前對象的_str
string(const string& s)
	:_str(nullptr)
{
	//調用構造函數
	string temp(s._str);
	//交換以后temp指向空,函數退出后被銷毀
	swap(_str, temp._str);
}

賦值運算符重載函數

步驟:

  • 判斷是否為自己給自己賦值
  • 調用拷貝構造函數定義臨時變量
  • 交換臨時變量與當前對象的_str
string& operator=(string& s)
{
	if (this != &s)
	{
		string temp(s);
		swap(_str, s._str);
	}
	return *this;
}

更簡潔的寫法:

string& operator=(string s)
{
	//傳參調用拷貝構造函數,不用判斷是否給自己賦值
	swap(_str, s._str);
	return *this;
}

析構函數

~string()
{
	if (_str)
	{
		delete[] _str;
		_str = nullptr;
	}
}

總結

原文鏈接:https://blog.csdn.net/qq_44631587/article/details/126271106

相關推薦

欄目分類
最近更新