C++之string的模擬實(shí)現(xiàn)過程
手寫C++字符串類
從零實(shí)現(xiàn)一個(gè)簡(jiǎn)易版std::string
類的基本結(jié)構(gòu)與成員變量
namespace zzh { class string { private: char* _str; // 存儲(chǔ)字符串的字符數(shù)組 size_t _size; // 當(dāng)前字符串長(zhǎng)度 size_t _capacity; // 已分配的容量 public: static const size_t npos; // 表示"不存在的位置" // 各類成員函數(shù)... }; }
這個(gè)自定義字符串類主要通過動(dòng)態(tài)分配的字符數(shù)組_str
來存儲(chǔ)字符串內(nèi)容,并維護(hù)兩個(gè)重要狀態(tài):_size
表示當(dāng)前字符串長(zhǎng)度,_capacity
表示已分配的內(nèi)存容量。
1.基本成員變量
在自定義 string 類中,我們需要定義一些基本的成員變量來存儲(chǔ)字符串的內(nèi)容和相關(guān)信息:
_str
:用于存儲(chǔ)字符串的字符數(shù)組,通常是一個(gè)動(dòng)態(tài)分配的 char 類型數(shù)組。_size
:表示當(dāng)前字符串的實(shí)際長(zhǎng)度,不包括結(jié)尾的空字符 \0。_capacity
:表示分配的內(nèi)存容量,通常大于或等于 _size,用于優(yōu)化內(nèi)存分配效率。
2.構(gòu)造函數(shù)和析構(gòu)函數(shù)
構(gòu)造函數(shù)用于初始化 string 對(duì)象,常見的構(gòu)造方式包括:
- 從 C 風(fēng)格字符串構(gòu)造(const char*):通過 strlen 計(jì)算字符串長(zhǎng)度,并動(dòng)態(tài)分配內(nèi)存來存儲(chǔ)字符串內(nèi)容。
- 拷貝構(gòu)造函數(shù):用于從另一個(gè) string 對(duì)象構(gòu)造新對(duì)象,需要深拷貝內(nèi)存以避免懸掛指針問題。
- 默認(rèn)構(gòu)造函數(shù):用于創(chuàng)建一個(gè)空字符串。
- 析構(gòu)函數(shù)則負(fù)責(zé)釋放動(dòng)態(tài)分配的內(nèi)存,避免內(nèi)存泄漏。
3.賦值運(yùn)算符重載
- 為了支持對(duì)象之間的賦值操作,我們需要重載賦值運(yùn)算符 =。
- 在實(shí)現(xiàn)時(shí),需要注意自賦值的情況,并進(jìn)行深拷貝以確保兩個(gè)對(duì)象的內(nèi)存獨(dú)立。
4.內(nèi)存管理
- 字符串操作中,內(nèi)存管理是一個(gè)關(guān)鍵問題。
- 我們需要在字符串長(zhǎng)度超過當(dāng)前容量時(shí)動(dòng)態(tài)擴(kuò)展內(nèi)存。
- 通常的做法是將容量加倍,以減少頻繁的內(nèi)存分配操作。
5.迭代器支持
- 為了方便遍歷字符串中的字符,我們可以提供迭代器支持。
- 通過定義 begin() 和 end() 方法,返回指向字符串首尾的指針,可以方便地使用標(biāo)準(zhǔn)庫算法。
6.常見操作實(shí)現(xiàn)
追加字符或字符串:通過 push_back 和 append 方法,可以在字符串末尾添加字符或另一個(gè)字符串的內(nèi)容。在實(shí)現(xiàn)時(shí),需要注意內(nèi)存容量是否足夠,并在必要時(shí)進(jìn)行擴(kuò)展。
- 查找和替換:提供 find 方法用于查找字符或子字符串的位置,insert 和 erase 方法用于插入和刪除字符或子字符串。
- 比較操作:重載比較運(yùn)算符(如 <、>、== 等),以便可以直接比較兩個(gè) string 對(duì)象的大小。
一、構(gòu)造函數(shù)與析構(gòu)函數(shù)
// 1. 從C風(fēng)格字符串構(gòu)造 string::string(const char* str) { _size = strlen(str); _str = new char[_size + 1]; _capacity = _size; memcpy(_str, str, _size + 1); } // 2. 拷貝構(gòu)造函數(shù) string::string(const string& s) { _size = s._size; _capacity = s._capacity; _str = new char[_capacity + 1]; memcpy(_str, s._str, _size + 1); } // 3. 析構(gòu)函數(shù) string::~string() { delete[] _str; _str = nullptr; _size = 0; _capacity = 0; }
關(guān)鍵點(diǎn):
- 構(gòu)造函數(shù)負(fù)責(zé)分配內(nèi)存并復(fù)制字符串內(nèi)容
- 拷貝構(gòu)造函數(shù)實(shí)現(xiàn)深拷貝,避免內(nèi)存共享
- 析構(gòu)函數(shù)必須釋放動(dòng)態(tài)分配的內(nèi)存,防止內(nèi)存泄漏
二、賦值運(yùn)算符重載
string& string::operator=(const string& s) { if (this != &s) { char* tmp = new char[s._capacity + 1]; memcpy(tmp, s._str, s._size + 1); delete[] _str; // 注意:原代碼此處順序有誤,已修正 _str = tmp; _size = s._size; _capacity = s._capacity; } return *this; }
技術(shù)要點(diǎn):
- 使用臨時(shí)變量確保異常安全
- 自我賦值檢查避免無效操作
- 先分配新內(nèi)存再釋放舊內(nèi)存,防止內(nèi)存泄漏
三、迭代器支持
string::iterator string::begin() { return _str; } string::iterator string::end() { return _str + _size; }
說明:
- 迭代器本質(zhì)是字符指針
begin()
返回字符串首地址end()
返回字符串末尾的下一個(gè)位置
四、內(nèi)存管理與擴(kuò)容機(jī)制
// 預(yù)分配內(nèi)存 void string::reserve(size_t n) { if (n > _capacity) { char* tmp = new char[n + 1]; memcpy(tmp, _str, _size + 1); delete[] _str; _str = tmp; _capacity = n; } } // 追加字符 void string::push_back(char c) { if (_size >= _capacity) { size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity; reserve(newcapacity); } _str[_size++] = c; // 注意:原代碼此處錯(cuò)誤地寫入了固定字符'c' _str[_size] = '\0'; }
內(nèi)存管理策略:
- 采用指數(shù)級(jí)擴(kuò)容(2倍)減少內(nèi)存分配次數(shù)
reserve()
實(shí)現(xiàn)預(yù)分配,避免頻繁擴(kuò)容- 每次擴(kuò)容后保留額外空間,提高插入效率
五、字符串操作函數(shù)
// 追加C風(fēng)格字符串 void string::append(const char* str) { size_t len = strlen(str); if (_size + len > _capacity) { size_t newcapacity = 2 * _capacity > _size + len ? 2 * _capacity : _size + len; reserve(newcapacity); } memcpy(_str + _size, str, len); // 注意:原代碼此處多復(fù)制了一個(gè)終止符 _size += len; _str[_size] = '\0'; // 手動(dòng)添加終止符 } // 查找字符 size_t string::find(char c, size_t pos = 0) const { for (size_t i = pos; i < _size; i++) { if (_str[i] == c) return i; } return npos; } // 插入字符 string& string::insert(size_t pos, char c) { assert(pos <= _size); if (_size >= _capacity) { size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity; reserve(newcapacity); } // 從后向前移動(dòng)元素 for (size_t i = _size; i > pos; i--) _str[i] = _str[i - 1]; _str[pos] = c; _size++; return *this; }
核心算法:
append()
通過內(nèi)存拷貝實(shí)現(xiàn)高效追加find()
線性查找目標(biāo)字符insert()
通過元素后移實(shí)現(xiàn)插入操作- 使用
memmove()
處理內(nèi)存重疊情況
六、運(yùn)算符重載
// 比較運(yùn)算符 bool string::operator<(const string& s) { size_t i1 = 0, i2 = 0; while (i1 < _size && i2 < s._size) { if (_str[i1] < s._str[i2]) return true; else if (_str[i1] > s._str[i2]) return false; i1++; i2++; } return i1 < s._size; // 注意:原代碼此處邏輯有誤,已修正 } // 索引運(yùn)算符 char& string::operator[](size_t index) { assert(index < _size); return _str[index]; }
實(shí)現(xiàn)要點(diǎn):
- 比較運(yùn)算符按字典序逐字符比較
- 索引運(yùn)算符提供隨機(jī)訪問能力
- 提供常量和非常量?jī)蓚€(gè)版本的重載
總結(jié)
通過手寫這個(gè)簡(jiǎn)易版string
類,我們深入理解了標(biāo)準(zhǔn)庫字符串類的核心機(jī)制:動(dòng)態(tài)內(nèi)存管理、深拷貝實(shí)現(xiàn)、迭代器設(shè)計(jì)、擴(kuò)容策略等。
雖然現(xiàn)代C++編程中應(yīng)優(yōu)先使用std::string
,但掌握這些底層原理有助于寫出更高效、更安全的代碼。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C++使用標(biāo)準(zhǔn)庫實(shí)現(xiàn)事件和委托以及信號(hào)和槽機(jī)制
這篇文章主要為大家詳細(xì)介紹了C++如何使用標(biāo)準(zhǔn)庫實(shí)現(xiàn)事件和委托以及信號(hào)和槽機(jī)制,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2022-11-11C++實(shí)現(xiàn)冒泡排序(BubbleSort)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)冒泡排序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04簡(jiǎn)單掌握C++編程中的while與do-while循環(huán)語句使用
這篇文章主要介紹了C++編程中的while與do-while循環(huán)語句使用,區(qū)別就是while是先判斷再執(zhí)行,而do-while是先執(zhí)行再判斷,需要的朋友可以參考下2016-01-01Cocos2d-x UI開發(fā)之文本類使用實(shí)例
這篇文章主要介紹了Cocos2d-x學(xué)習(xí)筆記之文本類,文本類是UI開發(fā)中經(jīng)常使用的,本文用詳細(xì)的代碼注釋講解了文本類的使用,需要的朋友可以參考下2014-09-09C++實(shí)現(xiàn)完整功能的通訊錄管理系統(tǒng)詳解
來了來了,通訊錄管理系統(tǒng)踏著七彩祥云飛來了,結(jié)合前面的結(jié)構(gòu)體知識(shí)和分文件編寫方法,我總結(jié)并碼了一個(gè)帶菜單的通訊錄管理系統(tǒng),在這篇文章中將會(huì)提到C的清空屏幕函數(shù),嵌套結(jié)構(gòu)體具體實(shí)現(xiàn),簡(jiǎn)單且充實(shí),跟著我的思路,可以很清晰的解決這個(gè)項(xiàng)目2022-05-05