C++深淺拷貝及簡(jiǎn)易string類實(shí)現(xiàn)方式
三種拷貝方式
淺拷貝
對(duì)于自定義的string類,如果不顯式定義拷貝構(gòu)造函數(shù),編譯器會(huì)默認(rèn)生成拷貝構(gòu)造函數(shù),此時(shí)的拷貝方式是淺拷貝,兩個(gè)對(duì)象會(huì)公用一塊兒內(nèi)存,析構(gòu)時(shí)同一空間被釋放兩次,會(huì)導(dǎo)致程序崩潰。
賦值運(yùn)算符重載也會(huì)產(chǎn)生同樣的問(wèn)題,同時(shí),由于被賦值對(duì)象原來(lái)有空間,淺拷貝還會(huì)導(dǎo)致舊的空間無(wú)法找到,造成內(nèi)存泄漏。
深拷貝
類中設(shè)計(jì)到資源的管理,拷貝構(gòu)造函數(shù)、賦值運(yùn)算符重載以及析構(gòu)函數(shù)都要顯示給出,按照深拷貝的方式。
深拷貝的方式讓每個(gè)對(duì)象都獨(dú)立擁有一份資源,不會(huì)造成多次釋放導(dǎo)致程序崩潰的問(wèn)題。
寫時(shí)拷貝
寫時(shí)拷貝是通過(guò)淺拷貝+引用計(jì)數(shù)的方式來(lái)實(shí)現(xiàn)的,引用計(jì)數(shù)是用來(lái)記錄資源的被引用的次數(shù),
可以將這種寫時(shí)拷貝的機(jī)制想象成“拖延癥”,只有當(dāng)不得不進(jìn)行拷貝時(shí),才會(huì)開辟新空間進(jìn)行拷貝
VS與GCC中的拷貝方式
Windows VS2022
VS中采用的是深拷貝的方式
Linux GCC
GCC編譯器采用的是寫時(shí)拷貝的方式
簡(jiǎn)易string類
簡(jiǎn)易string類主要實(shí)現(xiàn)四個(gè)功能,即構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)、析構(gòu)函數(shù)、賦值運(yùn)算符重載,主要考察深淺拷貝
實(shí)現(xiàn)簡(jiǎn)易string類有兩種代碼風(fēng)格,一種傳統(tǒng)版寫法,代碼復(fù)用性第,可讀性較好;另一種稱為現(xiàn)代版寫法,代碼復(fù)用性高,但是較難理解。
傳統(tǒng)版寫法的string類
構(gòu)造函數(shù)
步驟:
- 判斷是否為空指針,string類不允許nullptr構(gòu)造對(duì)象
- 申請(qǐng)新空間
- 將字符串中的值拷貝到申請(qǐng)的空間
string(const char* str = "") { if (nullptr == str) { assert(false); return; } //+1是因?yàn)橛?\0',strcpy會(huì)將源字符串中的'\0'拷貝到目標(biāo)空間 _str = new char[strlen(str) + 1]; strcpy(_str, str); }
拷貝構(gòu)造函數(shù)
步驟:
- 開辟空間
- 用源對(duì)象的_str給當(dāng)前對(duì)象的_str賦值
string(const string& s) :_str(new char[strlen(s._str) + 1]) { strcpy(_str, s._str); }
賦值運(yùn)算符重載
步驟:
- 判斷是否自己給自己賦值
- 開辟新空間
- 拷貝元素
- 刪除舊空間
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; }
另一種寫法
這種寫法不用定義臨時(shí)變量,代碼相對(duì)簡(jiǎn)潔一點(diǎn),但是如果new申請(qǐng)空間失敗,舊的空間也無(wú)法找到。
析構(gòu)函數(shù)
步驟:
- 釋放空間
- 將指針置為空
~string() { ?? ?if (_str) ?? ?{ ?? ??? ?delete[]_str; ?? ??? ?_str = nullptr; ?? ?} }
現(xiàn)代版寫法string類
構(gòu)造函數(shù)
string(const char* str = "") { if (str == nullptr) { assert(false); } _str = new char[strlen(str) + 1]; strcpy(_str, str); }
拷貝構(gòu)造函數(shù)
拷貝構(gòu)造函數(shù)中利用構(gòu)造函數(shù),實(shí)現(xiàn)了代碼的復(fù)用
步驟:
- 在初始化列表中將_str置為空
- 定義一個(gè)臨時(shí)的string類對(duì)象,指向要拷貝的對(duì)象相同位置
- 交換臨時(shí)對(duì)象與當(dāng)前對(duì)象的_str
string(const string& s) :_str(nullptr) { //調(diào)用構(gòu)造函數(shù) string temp(s._str); //交換以后temp指向空,函數(shù)退出后被銷毀 swap(_str, temp._str); }
賦值運(yùn)算符重載函數(shù)
步驟:
- 判斷是否為自己給自己賦值
- 調(diào)用拷貝構(gòu)造函數(shù)定義臨時(shí)變量
- 交換臨時(shí)變量與當(dāng)前對(duì)象的_str
string& operator=(string& s) { if (this != &s) { string temp(s); swap(_str, s._str); } return *this; }
更簡(jiǎn)潔的寫法:
string& operator=(string s) { //傳參調(diào)用拷貝構(gòu)造函數(shù),不用判斷是否給自己賦值 swap(_str, s._str); return *this; }
析構(gòu)函數(shù)
~string() { if (_str) { delete[] _str; _str = nullptr; } }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)登錄注冊(cè)和忘記密碼功能
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)登錄、注冊(cè)和忘記密碼功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12C語(yǔ)言實(shí)現(xiàn)無(wú)規(guī)律數(shù)據(jù)加密、解密功能
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)無(wú)規(guī)律數(shù)據(jù)加密、解密功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03C++求解二叉樹的下一個(gè)結(jié)點(diǎn)問(wèn)題
本文將通過(guò)C++求解以下問(wèn)題:給定一個(gè)二叉樹其中的一個(gè)結(jié)點(diǎn),請(qǐng)找出中序遍歷順序的下一個(gè)結(jié)點(diǎn)并且返回。文中示例代碼講解詳細(xì),感興趣的可以了解一下2022-04-04C語(yǔ)言求解最長(zhǎng)公共子字符串問(wèn)題及相關(guān)的算法分析
最長(zhǎng)公共子字符串問(wèn)題即是求一個(gè)字符串在另一個(gè)字符串中出現(xiàn)的連續(xù)最多字符,這里我們來(lái)看一下面試中經(jīng)常出現(xiàn)的C語(yǔ)言求解最長(zhǎng)公共子字符串問(wèn)題及相關(guān)的算法分析2016-06-06Qt5實(shí)現(xiàn)文本編輯器(附詳細(xì)代碼)
QT是一個(gè)跨平臺(tái)的GUI開發(fā)框架,我使用的QT5 C++版本的,本文主要介紹了Qt5實(shí)現(xiàn)文本編輯器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07VSCode同時(shí)更改所有相同的變量名或類名的圖文教程
這篇文章主要介紹了VSCode同時(shí)更改所有相同的變量名或類名,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05vs2022啟動(dòng)一個(gè)CmakeLists.txt項(xiàng)目的實(shí)踐
本文主要介紹了vs2022啟動(dòng)一個(gè)CmakeLists.txt項(xiàng)目的實(shí)踐,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06