浅拷贝+引用计数--写时拷贝---模拟实现string容器
引用計數
深拷貝
多個對象共享同一份資源時,最后能夠保證該資源只被釋放一次
應該由哪個對象釋放資源?
由最后一個使用該資源的對象去釋放
怎么知道一個對象是最后一個使用該資源的對象?
給一個計數,記錄使用該資源對象的個數
實現
計數用普通整型
先來看一個例子
class string { public:string(char *str = ""){//如果指針為空,則初始化位空字符串if (nullptr == str)str = "";//申請空間_str = new char[strlen(str) + 1];//初始化一個對象占一個資源,引用計數+1_count = 1;//拷貝數據strcpy(_str, str);}string( string& s):_str(s._str), _count(++s._count){}string& operator=(const string& s){//自己給自己賦值,不用做任何操作if (this != &s){}return *this;}~string(){//每次釋放對象計數都要減一,減完之后要看_count是不是0if (_str && 0 == --_count)delete[]_str;_str = nullptr;}//編譯器生成的默認賦值運算符重載存在淺拷貝,而且會有資源泄露,沒有釋放資源 private:char * _str;int _count; };在類中增加一個變量記錄使用資源的對象數
在類中增加int類型的成員變量----不行,因為這種變量每個對象都存在一份
普通的成員變量,每個對象都有一份,一個對象在修改計數時,不會影響其他對象
導致:資源沒有釋放而引起內存泄露
將計數變為靜態成員變量
class string { public:string(char *str = ""){//如果指針為空,則初始化位空字符串if (nullptr == str)str = "";//申請空間_str = new char[strlen(str) + 1];//初始化一個對象占一個資源,引用計數+1_count = 1;//拷貝數據strcpy(_str, str);}string(string& s) //靜態成員變量不能再在初始化列表中使用:_str(s._str){++_count;}string& operator=(const string& s){//自己給自己賦值,不用做任何操作if (this != &s){}return *this;}~string(){//每次釋放對象計數都要減一,減完之后要看_count是不是0if (_str && 0 == --_count)delete[]_str;_str = nullptr;}//編譯器生成的默認賦值運算符重載存在淺拷貝,而且會有資源泄露,沒有釋放資源 private:char * _str;static int _count; };int string::_count = 0;將計數給成靜態類型成員變量----不行
靜態類型成員是所有對象共享,計數應該與資源個數保持一致,有多少資源就要要多少計數
計數為整型指針類型
一個對象修改,另外一個對象也能看見
引用計數也有缺陷
如果出現這種情況
這種情況程序走到末尾,4個對象共用同一塊空間,如果用[]運算符去修改對象s1的值,那么其他對象也都被修改
寫時拷貝
所有對象共享一份資源時,讀數據不用拷貝,一但有對象要修改,則單獨為該對象拷貝一份資源
所以當出現所有寫操作或者可能會引起寫操作的方法,都會把當前對象修改掉,所以要分離對象’
寫時拷貝單線程底下沒有問題,但在多線程下可能會出錯
線程1計數減過了但是時間片到了,還沒來的及與0比較。線程2過來,發現資源還存在,而且線程2時間片充足,就會去釋放資源。釋放完后,線程1又開始執行,發現計數已經變為0,就會把資源再釋放一次,也會造成代碼崩潰
模擬實現string
namespace bite {class string{public:typedef char* iterator;public:string(const char* str = ""){if (str == nullptr)str = "";//當前對象開辟空間_size = strlen(str);_capacity = _size ;_str = new char[_capacity + 1];//拷貝元素strcpy(_str, str);}//放入n個字符chstring(size_t n, char ch):_size(n), _capacity(n), _str(new char[n + 1])//此處不能new char[_capacity],因為成員變量初始化,只跟聲明順序有關,_str先于_capacity聲明,所以//先初始化{memset(_str, ch, n);_str[n] = '\0'; //最后一個位置設置為\0}//[begin,end)string(char* begin, char* end){_size = end - begin;_capacity = _size;_str = new char[_size + 1];strncpy(_str, begin, _size);_str[_size] = '\0';}string(const string& s):_size(s._size), _capacity(s._size){_str = new char[_capacity + 1];strcpy(_str, s._str);}string& operator=(const string& s){if (this != &s){int len = strlen(s._str) ;char * p = new char[len + 1];strcpy(p, s._str);delete[]_str;_str = p;_size = len;_capacity = len;}return *this;}~string(){if (_str){delete[]_str;_str = nullptr;_capacity = 0;_size = 0;}}//容量相關操作size_t size()const{return _size;}size_t capacity()const{return _capacity;}bool empty()const{return 0 == _size;}void resize(size_t newsize,char ch){size_t oldsize = _size;if (newsize > oldsize){//有效元素增多//多出的元素再空余空間能否放的下if (newsize > _capacity){reserve(newsize);}memset(_str + _size, ch, newsize-oldsize);}_size = newsize;_str[_size] = '\0';}void reserve(size_t newcapacity){size_t oldcapacity = _capacity;if (newcapacity > oldcapacity){//申請新空間char * temp = new char[newcapacity + 1];//拷貝元素strcpy(temp, _str);//釋放舊空間delete[]_str;//指向新空間_str = temp;_capacity = newcapacity;}}//元素訪問相關操作char& operator[](size_t index){assert(index < _size);return _str[index];}const char& operator[]( int index){assert(index < _size);return _str[index];}//元素修改操作void push_back(char ch){if (_size == _capacity)reserve(_capacity * 2);_str[_size++] = ch;_str[_size] = '\0';}string& operator+=(const char ch){push_back(ch);return *this;}string& operator+=(const string s);bool operator==(const string s);bool operator!=(const string s);bool operator>=(const string s);bool operator<=(const string s);bool operator>(const string s);bool operator<(const string s);friend ostream& operator<< (ostream& _cout, const bite::string& s){_cout << s.c_str();return _cout;}friend istream operator>>(istream _cin, string s);//迭代器iterator begin(){return _str;}iterator end(){return _str + _size;}//特殊操作size_t find(char ch, size_t pos = 0){for (size_t i = pos; i < _size; i++){if (ch == _str[i])return i;}return npos;}size_t rfind(char ch, size_t pos = npos){if (pos == npos)pos = _size - 1;for (int i = pos; i >= 0; i--){if (ch == _str[i])return i;}return npos;}string substr(size_t pos = 0, size_t n = npos){if (n == npos)n = _size;string temp(_str + pos, _str + n + pos);return temp;}const char* c_str()const{return _str;}private:size_t _capacity; //當前空間有多大size_t _size; //當前string里有多少個有效字符char *_str;static size_t npos;};size_t string::npos = -1; }要使用范圍for進行打印,必須要給出begin()和end()
總結
以上是生活随笔為你收集整理的浅拷贝+引用计数--写时拷贝---模拟实现string容器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 详解string容器(应用+模拟实现,s
- 下一篇: 详解vector容器(应用+模拟实现,v