網(wǎng)站換ip對優(yōu)化有影響嗎武漢百度推廣公司
??愿所有美好如期而遇
前言
我們模擬實現(xiàn)string類不是為了去實現(xiàn)他,而是為了了解他內(nèi)部成員函數(shù)的一些運行原理和時間復(fù)雜度,在將來我們使用時能夠合理地去使用他們。
為了避免我們模擬實現(xiàn)的string類與全局上的string類沖突(string類也在std命名空間中),我們用自己的命名空間包起來。
namespace A
{class string{static void test(){}}
}int main()
{A::string::test();
}
接下來我們開始模擬實現(xiàn)string類。
私有的成員變量,我們設(shè)計無符號整型計算有效字符數(shù)量的_size,以及記錄空間大小的_capacity,最后就是字符指針,我們將來開辟好一塊空間后存放字符串,將由他來指向。
namespace A {class string{private:size_t _size;size_t _capacity;char* _str;} }
構(gòu)造函數(shù):
默認(rèn)是空串,并且我們默認(rèn)比有效字符多開一個字節(jié)的空間,之后進(jìn)行拷貝。
string(const char* str = "") {_size = _capacity = strlen(str);_str = new char[_capacity + 1];strcpy(_str, str); }
?拷貝構(gòu)造函數(shù):
我們模擬實現(xiàn)string類,一定會有空間的開辟,一但對象涉及到拷貝,就不能是淺拷貝,否則會出現(xiàn)一塊空間兩次釋放,直接崩掉。
string(const string& str) {_capacity = str._capacity;_size = str._size;_str = new char[_capacity + 1];strcpy(_str, str.c_str()); }
?賦值運算符重載:
同拷貝構(gòu)造,對象也是不能值拷貝,否則會出現(xiàn)一塊空間釋放兩次。
?string& operator=(const string& str) {if (this != &str){_capacity = str._capacity;_size = str._size;char* tmp = new char[_capacity + 1];strcpy(tmp, str.c_str());delete[] _str;_str = tmp;} return *this; }
析構(gòu)函數(shù):
~string() {delete[] _str;_str = nullptr;_capacity = _size = 0; }
?將string轉(zhuǎn)換為const char*,我們會在strlen等C的接口處使用,比如strlen(s.c_str()),因為strlen他的參數(shù)是const char*類型的。
?const char* c_str() const {return _str; }
?四個迭代器
只有物理地址空間連續(xù)才可以像這樣,如果是鏈表,我們不能這樣做。
typedef char* iterator; typedef const char* const_iterator;iterator begin() {return _str; }iterator end() {return _str + _size; }const_iterator begin()const {return _str; }const_iterator end()const {return _str + _size; }
?尾插單個字符,_capacity和_size都是只考慮有效字符,我們在創(chuàng)建空間時默認(rèn)開空間比_capacity大一。
void push_back(char ch) {if (_size == _capacity){_capacity = 0 ? 4 : _capacity * 2;char* tmp = new char[_capacity + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;}_str[_size++] = ch;_str[_size] = '\0'; }
?reserve函數(shù),我們使用reserve重新開空間,也是只考慮有效字符。
我們實現(xiàn)的reserve不可以縮容。
void reserve(size_t n) {if (n > _capacity){char* tmp = _str;//比需求多開一個字節(jié)的空間_str = new char[n + 1];strcpy(_str, tmp);//別忘記_capacity_capacity = n;delete[] tmp;} }
?尾插字符串
void append(const char* str) {size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}strcpy(_str + _size, str);_size += len; }
?賦值運算符+=的重載
//三個版本的+=運算符重載 string& operator+=(const string& str) {append(str.c_str());return *this; }string& operator+=(const char* str) {append(str);return *this; }string& operator+=(char ch) {push_back(ch);return *this; }
?成員函數(shù)swap
//不用進(jìn)行深拷貝,直接交換地址和大小 void swap(string& s) {std::swap(_size, s._size);std::swap(_capacity, s._capacity);std::swap(_str, s._str); }
清空字符串函數(shù)
void clear() {memset(_str, 0, _size); }
返回有效字符數(shù)量 ,判斷是否為空
size_t size()const {return _size; }bool empty()const {return _size == 0; }
重載[]運算符,我們重載兩個版本的,重載const版本是因為我們有時候只讀,不寫,所以需要這樣的重載。
char& operator[](size_t index) {return _str[index]; }const char& operator[](size_t index)const {return _str[index]; }
?find函數(shù),找到后返回下標(biāo)。strstr找到后返回的是找到的字符串的首地址,否則返回空。
size_t find(char c, size_t pos) const {for (size_t i = pos; i < _size; i++){if (_str[i] == c){return i;}}return npos; }//hello world size_t find(const char* s, size_t pos = 0) const {char* tmp = strstr(_str, s);if (tmp == nullptr){return npos;}return tmp - _str; }
insert函數(shù),從pos位置插入單個字符,以及字符串
string& insert(size_t pos, char c) {assert(pos <= _size);if (_size == _capacity){_capacity = 0 ? 4 : _capacity * 2;char* tmp = new char[_capacity + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;}int end = _size;while (end >= (int)pos){_str[end + 1] = _str[end];end--;}_str[pos] = c;_size++;return *this; }//pos是下標(biāo) string& insert(size_t pos, const char* str) {assert(pos <= _size);int len = strlen(str);if (len + pos > _capacity){reserve(len + pos);}int end = _size;while (end >= (int)pos){_str[end + len] = _str[end];end--;}strncpy(_str + pos, str, len);_size += len;return *this; }
erase函數(shù),刪除從pos節(jié)點開始的len個字符
string& erase(size_t pos, size_t len) {//如果pos == size就和沒刪除一樣,相當(dāng)于刪\0assert(pos < _size);//從pos位置刪除len個字符,也就是pos后的字符全部刪掉//傳的len值接近npos,pos+len可能溢出,也會有未知錯誤if (len == npos || pos + len >= _size){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}return *this; }
substr,截取從pos位置開始長度為len的字符串 ,在他返回時,就是對象的值拷貝,會有臨時對象產(chǎn)生,臨時對象就需要我們自己寫的拷貝構(gòu)造函數(shù)了。
string substr(size_t pos = 0, size_t len = npos) {assert(pos < _size);int end;string str;//hello world 2 3if (len == npos || pos + len > _size){end = _size;}else{end = pos + len;}//記得給str擴(kuò)容str.reserve(end - pos);while (end > pos){str += _str[pos++];}return str; }