詳解C++中String類模擬實(shí)現(xiàn)以及深拷貝淺拷貝
詳解C++中String類模擬實(shí)現(xiàn)以及深拷貝淺拷貝
在C語(yǔ)言中/C++中,字符串是一個(gè)應(yīng)用很廣泛的類型,也是很基礎(chǔ)的類型,C語(yǔ)言并沒(méi)有直接處理字符串的操作而是采用字符指針和字符串?dāng)?shù)組進(jìn)行操作,而在C++中標(biāo)準(zhǔn)庫(kù)為我們封裝了一個(gè)字符串的類供我們使用,使用需要#inlcude <string>頭文件。我們也可以自己模擬實(shí)現(xiàn)一個(gè)簡(jiǎn)單的String類。
在模擬實(shí)現(xiàn)String類的過(guò)程中,不可避免的會(huì)遇到深拷貝淺拷貝的問(wèn)題,下面就深拷貝淺拷貝做一個(gè)簡(jiǎn)介。所謂深拷貝淺拷貝,簡(jiǎn)單來(lái)說(shuō)就是淺拷貝只是簡(jiǎn)單的將值拷貝過(guò)來(lái),用一個(gè)對(duì)象初始化另一個(gè)對(duì)象,只復(fù)制了成員,并沒(méi)有復(fù)制資源,使兩個(gè)對(duì)象同時(shí)指向了同一資源的。而深拷貝則是將資源和值一塊拷貝過(guò)來(lái),此時(shí)兩個(gè)對(duì)象各自占用資源,盡管值相同,但是互不影響。
下面通過(guò)代碼進(jìn)行對(duì)比:
//淺拷貝 class String { public: String(const char* s = "") { if (NULL == s) { _pStr = new char[1]; *_pStr = '\0'; } else { _pStr = new char[strlen(s) + 1]; strcpy(_pStr, s); } } String(const String& s) { _pStr = s._pStr; } String& operator=(const String& s) { if (this != &s) { _pStr = s._pStr; } return *this; } ~String() { if (NULL != _pStr) { delete[] _pStr; _pStr = NULL; } } private: char* _pStr; };
//深拷貝 class String { public: String(const char* s = "") { if (NULL == s) { _pStr = new char[1]; *_pStr = '\0'; } else { _pStr = new char[strlen(s) + 1]; strcpy(_pStr, s); } } String(const String& s) : _pStr(new char[strlen(s._pStr) + 1]) { strcpy(_pStr, s._pStr); } String& operator=(const String& s) { if (this != &s) { //先申請(qǐng)空間將s的內(nèi)容拷貝到一個(gè)臨時(shí)變量再去釋放原有的空間 char* temp = new char[strlen(s._pStr) + 1];//防止申請(qǐng)空間失敗連原有的空間都沒(méi)了 strcpy(temp, s._pStr); delete[] _pStr; _pStr = NULL; _pStr = temp; } return *this; } ~String() { if (NULL != _pStr) { delete[] _pStr; _pStr = NULL; } } private: char* _pStr; };
由圖可以看出,淺拷貝使得多個(gè)對(duì)象指向一塊空間,然而當(dāng)最后析構(gòu)的時(shí)候,比如c先釋放空間,而a,b卻不知道還要釋放空間便會(huì)產(chǎn)生重復(fù)釋放同一內(nèi)存的錯(cuò)誤。為此,我們可以對(duì)淺拷貝進(jìn)行一個(gè)優(yōu)化,例如在私有成員中加入一個(gè)int*
pCount來(lái)標(biāo)記一塊空間被幾個(gè)對(duì)象占用,當(dāng)只有一個(gè)對(duì)象占用如果進(jìn)行析構(gòu)便可釋放空間,否則只對(duì)*pCount--。
//淺拷貝優(yōu)化--帶有計(jì)數(shù)版本的String類,用指針指向計(jì)數(shù)的空間 class String { public: String(const char* s = "") : _pCount(new int(1)) { if (NULL == s) { _pStr = new char[1]; *_pStr = '\0'; } else { _pStr = new char[strlen(s) + 1]; strcpy(_pStr, s); } } String(const String& s) { _pStr = s._pStr; _pCount = s._pCount; (*_pCount)++; } String& operator=(const String& s) { if (this != &s) { if (--(*_pCount) == 0) { delete[] _pStr; delete _pCount; } _pStr = s._pStr; _pCount = s._pCount; (*_pCount)++; } return *this; } ~String() { if (NULL != _pStr && --(*_pCount) == 0) { delete[] _pStr; delete _pCount; } _pCount = NULL; _pStr = NULL; } private: char* _pStr; int* _pCount; };
最后再給出一種深拷貝的簡(jiǎn)潔版本,通過(guò)調(diào)用swap來(lái)簡(jiǎn)化操作,代碼如下:
//深拷貝的簡(jiǎn)潔寫法 class String { public: String(const char* s = "") { if (NULL == s) { _pStr = new char[1]; *_pStr = '\0'; } else { _pStr = new char[strlen(s) + 1]; strcpy(_pStr, s); } } String(String& s) :_pStr(NULL)//必須對(duì)_pStr初始化,防止釋放隨機(jī)值的空間 { String temp(s._pStr); swap(_pStr, temp._pStr); } String& operator=(String& s) { if (this != &s) { swap(_pStr, s._pStr); } return *this; } ~String() { if (NULL != _pStr) { delete[] _pStr; _pStr = NULL; } } private: char* _pStr; };
如有疑問(wèn)請(qǐng)留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
舉例講解C語(yǔ)言鏈接器的符號(hào)解析機(jī)制
鏈接器的工作主要分為兩個(gè)階段:符號(hào)解析和重定位,符號(hào)解析的功能是將每個(gè)模塊符號(hào)引用綁定到一個(gè)確切的符號(hào)定義,這里我們就來(lái)舉例講解C語(yǔ)言鏈接器的符號(hào)解析機(jī)制2016-05-05C++使用ImGUI框架開(kāi)發(fā)一個(gè)簡(jiǎn)單程序
ImGui?是一個(gè)用于C++的用戶界面庫(kù),跨平臺(tái)、無(wú)依賴,支持OpenGL、DirectX等多種渲染API,下面就跟隨小編一起學(xué)習(xí)一下如何使用ImGUI框架開(kāi)發(fā)一個(gè)簡(jiǎn)單程序吧2023-08-08詳解Qt中的雙緩沖機(jī)制與實(shí)例應(yīng)用
所謂雙緩沖機(jī)制,是指在繪制控件時(shí),首先將要繪制的內(nèi)容繪制在一個(gè)圖片中,再將圖片一次性地繪制到控件上。本文主要為大家介紹了Qt中的雙緩沖機(jī)制與實(shí)例應(yīng)用,希望對(duì)大家有所幫助2023-03-03C++實(shí)現(xiàn)將一個(gè)字符串中的字符替換成另一個(gè)字符串的方法
這篇文章主要介紹了C++實(shí)現(xiàn)將一個(gè)字符串中的字符替換成另一個(gè)字符串的方法,需要考慮的情況比較全面,有不錯(cuò)的借鑒價(jià)值,需要的朋友可以參考下2014-09-09C++?二叉樹(shù)的實(shí)現(xiàn)超詳細(xì)解析
二叉樹(shù)可以簡(jiǎn)單理解為對(duì)于一個(gè)節(jié)點(diǎn)來(lái)說(shuō),最多擁有一個(gè)上級(jí)節(jié)點(diǎn),同時(shí)最多具備左右兩個(gè)下級(jí)節(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu)。本文將詳細(xì)介紹一下C++中二叉樹(shù)的實(shí)現(xiàn)和遍歷,需要的可以參考一下2022-03-03C/C++?Linux?Socket網(wǎng)絡(luò)編程流程分析
這篇文章主要介紹了C/C++?Linux?Socket網(wǎng)絡(luò)編程,Linux環(huán)境中的C/C++?socket?與Window環(huán)境中的C/C++?socket類似,本文所記錄的是TCP協(xié)議的socket編程,圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02