日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

String类的模拟实现

發布時間:2024/3/13 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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類

現代寫法:借助中間變量,交換指針

#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:void swap(string& st) {::swap(_str, st._str);::swap(_size, st._size);::swap(_capacity, st._capacity);}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);}*///重載函數現代寫法//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;}*/};

三、傳統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类的模拟实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。