String类的模拟实现
目錄:
- 一、經典String類的問題
- 1,淺拷貝
- 2,深拷貝
- 二、現代寫法版的string類
- 三、傳統String類的模擬實現
- 1、迭代器
- 2、operator[]
- 3、size()
- 4、c_str()
- 6、operator=()
- 7、reserve
- 8、push_back
- 9、append
- 10、operator+=
- 11、insert
- 12、operator>
- 13、全部代碼
一、經典String類的問題
首先,看一段代碼
class string { public:/*string():_str(new char[1]){*_str = '\0';}*///string(const char* str = "\0") 錯誤示范//string(const char* str = nullptr) 錯誤示范string(const char* str = ""){// 構造string類對象時,如果傳遞nullptr指針,認為程序非法,此處斷言下if(nullptr == str){assert(false);return;}_str = new char[strlen(str) + 1];strcpy(_str, str);}~string(){if(_str){delete[] _str;_str = nullptr;}}private:char* _str; }; // 測試 void Teststring() { string s1("hello bit!!!");string s2(s1); }
說明:上述string類沒有顯式定義其拷貝構造函數與賦值運算符重載,此時編譯器會合成默認的,當用s1構造s2時,編譯器會調用默認的拷貝構造。最終導致的問題是,s1、s2共用同一塊內存空間,在釋放時同一塊空間被釋放多次而引起程序崩潰,這種拷貝方式,稱為淺拷貝
深拷貝和淺拷貝的示意圖大致如下:
1,淺拷貝
淺拷貝:也稱位拷貝,編譯器只是將對象中的值拷貝過來。如果對象中管理資源,最后就會導致多個對象共享同一份資源,當一個對象銷毀時就會將該資源釋放掉,而此時另一些對象不知道該資源已經被釋放,以為還有效,所以 當繼續對資源進項操作時,就會發生發生了訪問違規。
當我們把一個對象賦值給一個新的變量時,賦的其實是該對象的在棧中的地址,而不是堆中的數據。也就是兩個對象指向的是同一個存儲空間,無論哪個對象發生改變,其實都是改變的存儲空間的內容,因此,兩個對象是聯動的。
淺拷貝是按位拷貝對象,它會創建一個新對象,這個對象有著原始對象屬性值的一份精確拷貝。如果屬性是基本類型,拷貝的就是基本類型的值;如果屬性是內存地址(引用類型),拷貝的就是內存地址 ,因此如果其中一個對象改變了這個地址,就會影響到另一個對象。即默認拷貝構造函數只是對對象進行淺拷貝復制(逐個成員依次拷貝),即只復制對象空間而不復制資源。
2,深拷貝
一個引用對象一般來說由兩個部分組成:一個具名的Handle,也就是我們所說的聲明(如變量)和一個內部(不具名)的對象,也就是具名Handle的內部對象。它在Manged Heap(托管堆)中分配,一般由新增引用對象的New方法是進行創建。深拷貝是指源對象與拷貝對象互相獨立,其中任何一個對象的改動都不會對另外一個對象造成影響。舉個例子,一個人名叫張三,后來用他克隆(假設法律允許)了另外一個人,叫李四,不管是張三缺胳膊少腿還是李四缺胳膊少腿都不會影響另外一個人。比較典型的就是Value(值)對象,如預定義類型Int32,Double,以及結構(struct),枚舉(Enum)等
#include<iostream>using namespace std; class Pata { private:int a;public:Pata(int a) {this->a = a; }Pata(Pata& ast) {this->a = ast.a; } }; int main() {Pata s1(2);Pata s2(s1);return 0;}
this和ast地址不同
對象作為函數參數傳遞時,調用拷貝構造函數。
Pata(Pata& ast){} //系統默認另開辟一片空間,把ast復制到這片空間中去
如果改變s2的值不會改變s2的值。
二、現代寫法版的string類
現代寫法:借助中間變量,交換指針
三、傳統String類的模擬實現
傳統寫法:老老實實開辟空間并復制內容
1、迭代器
指針是良好的迭代器
/*typedef char* iterator;iterator begin() {return _str;}iterator end() {return _str+_size;}*/typedef const char* iterator;iterator begin() const{ return _str;}iterator end() const {return _str + _size;}這里使用迭代器實現遍歷打印
void print(const st::string& s ) {st::string::iterator it = s.begin();while (it<s.end()) {cout << *it;++it;}}}2、operator[]
char & operator[](size_t i) {assert(i < _size);return _str[i];}3、size()
size_t size() {return _size;}4、c_str()
const char* c_str() {return _str;}6、operator=()
//現代寫法//s1=s2string& operator=(string st) {this->swap( st);return *this;}/* string& operator=(const string &st) {if (this!= &st) {delete[] _str;_str = new char[strlen(st._str) + 1];strcpy(_str, st._str);}return *this;}*/7、reserve
void reserve(size_t n) {if (n > _capacity) {char* tem = new char[n+1];strcpy( tem,_str);delete[]_str;_str = tem;_capacity = n;}}void resize(size_t n, char ch = '\0') {if (n < _size) {_str[n] = '\0';_size = n;}else {if (n > _capacity) {reserve(n);} for (size_t i = _size; i < n; i++) {_str[i] = ch;}_str[n] = '\0';_size = n;}}8、push_back
void push_back(char ch) {if (_size == _capacity) {reserve(2 * _capacity);}_str[_size] = ch;++_size;_str[_size] = '\0';}9、append
void append(const char* ch) {size_t len = strlen(ch) + 1;if (_size +len> _capacity) {reserve(len+_size);}strcpy(_str + _size, ch);_size += len;}10、operator+=
}string& operator+=(char s) {push_back(s);return *this;}string& operator+=(const string &ss) {append(ss._str);return *this;}11、insert
void insert(size_t n,char ch) {if (_size == _capacity) {size_t capacity =( _capacity == 0) ? 8 : _capacity * 2;reserve(capacity);}int end = _size+1;while (n<end) {_str[end] = _str[end-1];--end;}_str[n] = ch;_size++;}void insert(size_t n, const char *ch) {size_t len = strlen(ch);if (_size + len > _capacity) {reserve(_size + len);}size_t end = _size+len;while (end >= n + len) {_str[end] = _str[end - len];--end;}strncpy(_str + n, ch,len );_size += len;}12、operator>
bool operator>(string s1, string s2) {size_t i = 0, j = 0;while (i < s1.size() && s2.size()) {if (s1[i] > s2[j]){return true;}else if (s1[i] < s2[j]) {return false;}else {i++; j++;}}if (i < s1.size()) {return true;}else if (j < s2.size()) {return false;}else {return true;}}13、全部代碼
#pragma warning(disable:4996) #include<iostream> #include<assert.h> using namespace std;namespace st {class string {private:char* _str;size_t _size;size_t _capacity;static const size_t npos;public://指針是天然的迭代器/*typedef char* iterator;iterator begin() {return _str;}iterator end() {return _str+_size;}*/typedef const char* iterator;iterator begin() const{ return _str;}iterator end() const {return _str + _size;}string(const char* st=" ") {_size = strlen(st);_capacity = _size;_str = new char[_capacity+1];strcpy(_str, st);}//拷貝構造的現代寫法//s2(s1)---string(const string& st):_str(nullptr)//s是局部對象出了作用域這個空間就會釋放,但不能對隨機指向的空間釋放,_size(0),_capacity(0){string s(st._str);//s這臨時變量指向st._strswap(s);}/* string(const string & st):_str(new char[strlen(st._str)+1]) {strcpy(_str, st._str);}*/char & operator[](size_t i) {assert(i < _size);return _str[i];}size_t size() {return _size;}~string() {delete[] _str;}const char* c_str() {return _str;}//現代寫法//s1=s2string& operator=(string st) {this->swap( st);return *this;}/* string& operator=(const string &st) {if (this!= &st) {delete[] _str;_str = new char[strlen(st._str) + 1];strcpy(_str, st._str);}return *this;}*/void reserve(size_t n) {if (n > _capacity) {char* tem = new char[n+1];strcpy( tem,_str);delete[]_str;_str = tem;_capacity = n;}}void resize(size_t n, char ch = '\0') {if (n < _size) {_str[n] = '\0';_size = n;}else {if (n > _capacity) {reserve(n);} for (size_t i = _size; i < n; i++) {_str[i] = ch;}_str[n] = '\0';_size = n;}}void push_back(char ch) {if (_size == _capacity) {reserve(2 * _capacity);}_str[_size] = ch;++_size;_str[_size] = '\0';}void append(const char* ch) {size_t len = strlen(ch) + 1;if (_size +len> _capacity) {reserve(len+_size);}strcpy(_str + _size, ch);_size += len;}string& operator+=(char s) {push_back(s);return *this;}string& operator+=(const string &ss) {append(ss._str);return *this;}void swap(string& st) {::swap(_str, st._str);::swap(_size, st._size);::swap(_capacity, st._capacity);}void insert(size_t n,char ch) {if (_size == _capacity) {size_t capacity =( _capacity == 0) ? 8 : _capacity * 2;reserve(capacity);}int end = _size+1;while (n<end) {_str[end] = _str[end-1];--end;}_str[n] = ch;_size++;}void insert(size_t n, const char *ch) {size_t len = strlen(ch);if (_size + len > _capacity) {reserve(_size + len);}size_t end = _size+len;while (end >= n + len) {_str[end] = _str[end - len];--end;}strncpy(_str + n, ch,len );_size += len;}void exit(size_t np,size_t npo=npos) {if (npo==npos||np + npo > _size) {_str[np] = '\0';_size = np;}else {strcpy(_str + np, _str + np + npo);_size -= npo;}}size_t find(char ch, size_t p = 0) {for (size_t i = 0; i < _size; i++) {if (_str[i] == ch) {return i;}}return npos;}size_t find(const char* ch, size_t p = 0) {const char* ret = strstr(_str + p, ch);if (ret == nullptr){return npos;}else{return ret - _str;}}};const size_t string::npos = -1;bool operator>(string s1, string s2) {size_t i = 0, j = 0;while (i < s1.size() && s2.size()) {if (s1[i] > s2[j]){return true;}else if (s1[i] < s2[j]) {return false;}else {i++; j++;}}if (i < s1.size()) {return true;}else if (j < s2.size()) {return false;}else {return true;}}ostream& operator<<(ostream& out, string& s){for (size_t i = 0; i < s.size(); ++i){out << s[i];}return out;}istream& operator>>(istream& in, string& s){s.resize(0);char ch;while (1){//in>>ch;in.get(ch);if (ch == ' ' || ch == '\n'){break;}else{s += ch;}}return in;}bool operator==(string &s1, string &s2) {size_t i = 0, j = 0;while (i < s1.size() && s2.size()) {if (s1[i] > s2[j]) {return false;}else if (s1[i] < s2[j]) {return false;}else {i++; j++;}}if (i == s1.size()&& j ==s2.size()) {return true;}else {return false;}} void print(const st::string& s ) {st::string::iterator it = s.begin();while (it<s.end()) {cout << *it;++it;}}} int main() {st::string s1("123456");st::string s2=s1;//s1.exit(2, 3);//print(s1);cout << s2;if (s1 == s2) {cout << "ok";}else {cout << "no";}return 0; }總結
以上是生活随笔為你收集整理的String类的模拟实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 可编辑的下拉选单
- 下一篇: 微软的MSR paraphrase数据集