浅拷贝+引用计数--写时拷贝---模拟实现string容器
引用計(jì)數(shù)
深拷貝
多個(gè)對(duì)象共享同一份資源時(shí),最后能夠保證該資源只被釋放一次
應(yīng)該由哪個(gè)對(duì)象釋放資源?
由最后一個(gè)使用該資源的對(duì)象去釋放
怎么知道一個(gè)對(duì)象是最后一個(gè)使用該資源的對(duì)象?
給一個(gè)計(jì)數(shù),記錄使用該資源對(duì)象的個(gè)數(shù)
實(shí)現(xiàn)
計(jì)數(shù)用普通整型
先來(lái)看一個(gè)例子
class string { public:string(char *str = ""){//如果指針為空,則初始化位空字符串if (nullptr == str)str = "";//申請(qǐng)空間_str = new char[strlen(str) + 1];//初始化一個(gè)對(duì)象占一個(gè)資源,引用計(jì)數(shù)+1_count = 1;//拷貝數(shù)據(jù)strcpy(_str, str);}string( string& s):_str(s._str), _count(++s._count){}string& operator=(const string& s){//自己給自己賦值,不用做任何操作if (this != &s){}return *this;}~string(){//每次釋放對(duì)象計(jì)數(shù)都要減一,減完之后要看_count是不是0if (_str && 0 == --_count)delete[]_str;_str = nullptr;}//編譯器生成的默認(rèn)賦值運(yùn)算符重載存在淺拷貝,而且會(huì)有資源泄露,沒(méi)有釋放資源 private:char * _str;int _count; };在類(lèi)中增加一個(gè)變量記錄使用資源的對(duì)象數(shù)
在類(lèi)中增加int類(lèi)型的成員變量----不行,因?yàn)檫@種變量每個(gè)對(duì)象都存在一份
普通的成員變量,每個(gè)對(duì)象都有一份,一個(gè)對(duì)象在修改計(jì)數(shù)時(shí),不會(huì)影響其他對(duì)象
導(dǎo)致:資源沒(méi)有釋放而引起內(nèi)存泄露
將計(jì)數(shù)變?yōu)殪o態(tài)成員變量
class string { public:string(char *str = ""){//如果指針為空,則初始化位空字符串if (nullptr == str)str = "";//申請(qǐng)空間_str = new char[strlen(str) + 1];//初始化一個(gè)對(duì)象占一個(gè)資源,引用計(jì)數(shù)+1_count = 1;//拷貝數(shù)據(jù)strcpy(_str, str);}string(string& s) //靜態(tài)成員變量不能再在初始化列表中使用:_str(s._str){++_count;}string& operator=(const string& s){//自己給自己賦值,不用做任何操作if (this != &s){}return *this;}~string(){//每次釋放對(duì)象計(jì)數(shù)都要減一,減完之后要看_count是不是0if (_str && 0 == --_count)delete[]_str;_str = nullptr;}//編譯器生成的默認(rèn)賦值運(yùn)算符重載存在淺拷貝,而且會(huì)有資源泄露,沒(méi)有釋放資源 private:char * _str;static int _count; };int string::_count = 0;將計(jì)數(shù)給成靜態(tài)類(lèi)型成員變量----不行
靜態(tài)類(lèi)型成員是所有對(duì)象共享,計(jì)數(shù)應(yīng)該與資源個(gè)數(shù)保持一致,有多少資源就要要多少計(jì)數(shù)
計(jì)數(shù)為整型指針類(lèi)型
一個(gè)對(duì)象修改,另外一個(gè)對(duì)象也能看見(jiàn)
引用計(jì)數(shù)也有缺陷
如果出現(xiàn)這種情況
這種情況程序走到末尾,4個(gè)對(duì)象共用同一塊空間,如果用[]運(yùn)算符去修改對(duì)象s1的值,那么其他對(duì)象也都被修改
寫(xiě)時(shí)拷貝
所有對(duì)象共享一份資源時(shí),讀數(shù)據(jù)不用拷貝,一但有對(duì)象要修改,則單獨(dú)為該對(duì)象拷貝一份資源
所以當(dāng)出現(xiàn)所有寫(xiě)操作或者可能會(huì)引起寫(xiě)操作的方法,都會(huì)把當(dāng)前對(duì)象修改掉,所以要分離對(duì)象’
寫(xiě)時(shí)拷貝單線(xiàn)程底下沒(méi)有問(wèn)題,但在多線(xiàn)程下可能會(huì)出錯(cuò)
線(xiàn)程1計(jì)數(shù)減過(guò)了但是時(shí)間片到了,還沒(méi)來(lái)的及與0比較。線(xiàn)程2過(guò)來(lái),發(fā)現(xiàn)資源還存在,而且線(xiàn)程2時(shí)間片充足,就會(huì)去釋放資源。釋放完后,線(xiàn)程1又開(kāi)始執(zhí)行,發(fā)現(xiàn)計(jì)數(shù)已經(jīng)變?yōu)?,就會(huì)把資源再釋放一次,也會(huì)造成代碼崩潰
模擬實(shí)現(xiàn)string
namespace bite {class string{public:typedef char* iterator;public:string(const char* str = ""){if (str == nullptr)str = "";//當(dāng)前對(duì)象開(kāi)辟空間_size = strlen(str);_capacity = _size ;_str = new char[_capacity + 1];//拷貝元素strcpy(_str, str);}//放入n個(gè)字符chstring(size_t n, char ch):_size(n), _capacity(n), _str(new char[n + 1])//此處不能new char[_capacity],因?yàn)槌蓡T變量初始化,只跟聲明順序有關(guān),_str先于_capacity聲明,所以//先初始化{memset(_str, ch, n);_str[n] = '\0'; //最后一個(gè)位置設(shè)置為\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;}}//容量相關(guān)操作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){//申請(qǐng)新空間char * temp = new char[newcapacity + 1];//拷貝元素strcpy(temp, _str);//釋放舊空間delete[]_str;//指向新空間_str = temp;_capacity = newcapacity;}}//元素訪(fǎng)問(wèn)相關(guān)操作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; //當(dāng)前空間有多大size_t _size; //當(dāng)前string里有多少個(gè)有效字符char *_str;static size_t npos;};size_t string::npos = -1; }要使用范圍for進(jìn)行打印,必須要給出begin()和end()
總結(jié)
以上是生活随笔為你收集整理的浅拷贝+引用计数--写时拷贝---模拟实现string容器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 详解string容器(应用+模拟实现,s
- 下一篇: 成都大熊猫繁育基地游览时间