C++之string的模擬實(shí)現(xiàn)過(guò)程
手寫(xiě)C++字符串類(lèi)
從零實(shí)現(xiàn)一個(gè)簡(jiǎn)易版std::string
類(lèi)的基本結(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; // 表示"不存在的位置"
// 各類(lèi)成員函數(shù)...
};
}這個(gè)自定義字符串類(lèi)主要通過(guò)動(dòng)態(tài)分配的字符數(shù)組_str來(lái)存儲(chǔ)字符串內(nèi)容,并維護(hù)兩個(gè)重要狀態(tài):_size表示當(dāng)前字符串長(zhǎng)度,_capacity表示已分配的內(nèi)存容量。
1.基本成員變量
在自定義 string 類(lèi)中,我們需要定義一些基本的成員變量來(lái)存儲(chǔ)字符串的內(nèi)容和相關(guān)信息:
_str:用于存儲(chǔ)字符串的字符數(shù)組,通常是一個(gè)動(dòng)態(tài)分配的 char 類(lèi)型數(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ì)象,常見(jiàn)的構(gòu)造方式包括:
- 從 C 風(fēng)格字符串構(gòu)造(const char*):通過(guò) strlen 計(jì)算字符串長(zhǎng)度,并動(dòng)態(tài)分配內(nèi)存來(lái)存儲(chǔ)字符串內(nèi)容。
- 拷貝構(gòu)造函數(shù):用于從另一個(gè) string 對(duì)象構(gòu)造新對(duì)象,需要深拷貝內(nèi)存以避免懸掛指針問(wèn)題。
- 默認(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)鍵問(wèn)題。
- 我們需要在字符串長(zhǎng)度超過(guò)當(dāng)前容量時(shí)動(dòng)態(tài)擴(kuò)展內(nèi)存。
- 通常的做法是將容量加倍,以減少頻繁的內(nèi)存分配操作。
5.迭代器支持
- 為了方便遍歷字符串中的字符,我們可以提供迭代器支持。
- 通過(guò)定義 begin() 和 end() 方法,返回指向字符串首尾的指針,可以方便地使用標(biāo)準(zhǔn)庫(kù)算法。
6.常見(jiàn)操作實(shí)現(xiàn)
追加字符或字符串:通過(guò) 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í)變量確保異常安全
- 自我賦值檢查避免無(wú)效操作
- 先分配新內(nèi)存再釋放舊內(nèi)存,防止內(nèi)存泄漏
三、迭代器支持
string::iterator string::begin() { return _str; }
string::iterator string::end() { return _str + _size; }說(shuō)明:
- 迭代器本質(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ò)誤地寫(xiě)入了固定字符'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()通過(guò)內(nèi)存拷貝實(shí)現(xiàn)高效追加find()線性查找目標(biāo)字符insert()通過(guò)元素后移實(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ī)訪問(wèn)能力
- 提供常量和非常量?jī)蓚€(gè)版本的重載
總結(jié)
通過(guò)手寫(xiě)這個(gè)簡(jiǎn)易版string類(lèi),我們深入理解了標(biāo)準(zhǔn)庫(kù)字符串類(lèi)的核心機(jī)制:動(dòng)態(tài)內(nèi)存管理、深拷貝實(shí)現(xiàn)、迭代器設(shè)計(jì)、擴(kuò)容策略等。
雖然現(xiàn)代C++編程中應(yīng)優(yōu)先使用std::string,但掌握這些底層原理有助于寫(xiě)出更高效、更安全的代碼。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C++使用標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn)事件和委托以及信號(hào)和槽機(jī)制
這篇文章主要為大家詳細(xì)介紹了C++如何使用標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn)事件和委托以及信號(hào)和槽機(jī)制,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2022-11-11
C語(yǔ)言完數(shù)的實(shí)現(xiàn)示例
C語(yǔ)言中的完數(shù)指的是一個(gè)正整數(shù),本文主要介紹了C語(yǔ)言完數(shù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
C++實(shí)現(xiàn)冒泡排序(BubbleSort)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)冒泡排序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04
簡(jiǎn)單掌握C++編程中的while與do-while循環(huán)語(yǔ)句使用
這篇文章主要介紹了C++編程中的while與do-while循環(huán)語(yǔ)句使用,區(qū)別就是while是先判斷再執(zhí)行,而do-while是先執(zhí)行再判斷,需要的朋友可以參考下2016-01-01
Cocos2d-x UI開(kāi)發(fā)之文本類(lèi)使用實(shí)例
這篇文章主要介紹了Cocos2d-x學(xué)習(xí)筆記之文本類(lèi),文本類(lèi)是UI開(kāi)發(fā)中經(jīng)常使用的,本文用詳細(xì)的代碼注釋講解了文本類(lèi)的使用,需要的朋友可以參考下2014-09-09
C++實(shí)現(xiàn)完整功能的通訊錄管理系統(tǒng)詳解
來(lái)了來(lái)了,通訊錄管理系統(tǒng)踏著七彩祥云飛來(lái)了,結(jié)合前面的結(jié)構(gòu)體知識(shí)和分文件編寫(xiě)方法,我總結(jié)并碼了一個(gè)帶菜單的通訊錄管理系統(tǒng),在這篇文章中將會(huì)提到C的清空屏幕函數(shù),嵌套結(jié)構(gòu)體具體實(shí)現(xiàn),簡(jiǎn)單且充實(shí),跟著我的思路,可以很清晰的解決這個(gè)項(xiàng)目2022-05-05
利用C語(yǔ)言編寫(xiě)一個(gè)無(wú)限循環(huán)語(yǔ)句
這篇文章主要介紹了利用C語(yǔ)言編寫(xiě)一個(gè)無(wú)限循環(huán)語(yǔ)句問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
C++模擬Linux Shell編寫(xiě)一個(gè)自定義命令
這篇文章主要介紹了C++如何模擬Linux Shell實(shí)現(xiàn)編寫(xiě)一個(gè)自定義命令,本文通過(guò)實(shí)例代碼進(jìn)行命令行解析,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12

