百盛联合建设集团有限公司网站,唐山软件开发公司排名,怎样做营销型网站,标准网站有哪些引用计数
深拷贝 多个对象共享同一份资源时#xff0c;最后能够保证该资源只被释放一次 应该由哪个对象释放资源#xff1f; 由最后一个使用该资源的对象去释放 怎么知道一个对象是最后一个使用该资源的对象#xff1f; 给一个计数#xff0c;记录使用该资源对象的个数
实…引用计数
深拷贝 多个对象共享同一份资源时最后能够保证该资源只被释放一次 应该由哪个对象释放资源 由最后一个使用该资源的对象去释放 怎么知道一个对象是最后一个使用该资源的对象 给一个计数记录使用该资源对象的个数
实现
计数用普通整型
先来看一个例子
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;将计数给成静态类型成员变量----不行 静态类型成员是所有对象共享计数应该与资源个数保持一致有多少资源就要要多少计数
计数为整型指针类型 一个对象修改另外一个对象也能看见
class string{public:string(char *str ):_pCount(new int (1)){//如果指针为空则初始化位空字符串if (nullptr str)str ;//申请空间_str new char[strlen(str) 1];//拷贝数据strcpy(_str, str);}string(string s) //静态成员变量不能再在初始化列表中使用:_str(s._str) //两个对象共用同一份资源, _pCount(s._pCount) //两个对象共用一个计数{(*_pCount);}//s2 s1//s2原来的资源将不再使用---应该给原来的计数-1// 计数非0:// 计数为0: 释放掉原来的资源//s2应该与s1共享同一份资源计数string operator(const string s){//自己给自己赋值不用做任何操作if (this ! s){//让当前对象与其管理的资源分离开if (0 --*_pCount){delete[]_str;delete _pCount;}//与s共享资源_str s._str;_pCount s._pCount; (*_pCount);}return *this;}~string(){//每次释放对象计数都要减一减完之后要看_count是不是0if (_str 0 -- *_pCount){delete[]_str;_str nullptr;delete _pCount;_pCount nullptr;}}private:char * _str;int* _pCount;};引用计数也有缺陷 如果出现这种情况
void TestString()
{bite::string s1(hello);bite::string s2(s1);bite::string s3(world);bite::string s4(s3);s3 s1; //s3不需要释放原来的资源因为还有s4在用s1 s4; //s4是最后使用资源的对象所以需要释放
}这种情况程序走到末尾4个对象共用同一块空间如果用[]运算符去修改对象s1的值那么其他对象也都被修改
写时拷贝
所有对象共享一份资源时读数据不用拷贝一但有对象要修改则单独为该对象拷贝一份资源 所以当出现所有写操作或者可能会引起写操作的方法都会把当前对象修改掉所以要分离对象’
namespace bite
{class string{public:string(char *str ):_pCount(new int (1)){//如果指针为空则初始化位空字符串if (nullptr str)str ;//申请空间_str new char[strlen(str) 1];//拷贝数据strcpy(_str, str);}string(string s) //静态成员变量不能再在初始化列表中使用:_str(s._str) //两个对象共用同一份资源, _pCount(s._pCount) //两个对象共用一个计数{(*_pCount);}//s2 s1//s2原来的资源将不再使用---应该给原来的计数-1// 计数非0:// 计数为0: 释放掉原来的资源//s2应该与s1共享同一份资源计数string operator(const string s){//自己给自己赋值不用做任何操作if (this ! s){//让当前对象与其管理的资源分离开if (0 --*_pCount){delete[]_str;delete _pCount;}//与s共享资源_str s._str;_pCount s._pCount; (*_pCount);}return *this;}char operator[](size_t index){//该操作可能会改变当前对象的内容//必须分离当前对象if (GetRef() 1){string strtemp(_str);//构造临时对象this-swap(strtemp); //当前对象与临时对象交换}return _str[index];}~string(){//每次释放对象计数都要减一减完之后要看_count是不是0if (_str 0 -- *_pCount){delete[]_str;_str nullptr;delete _pCount;_pCount nullptr;}}void swap(string s){std::swap(_str, s._str);std::swap(_pCount, s._pCount);}private://获取引用计数int GetRef(){return *_pCount;}private:char * _str;int* _pCount;};
}void TestString()
{bite::string s1(hello);bite::string s2(s1);bite::string s3(world);bite::string s4(s3);s3 s1; //s3不需要释放原来的资源因为还有s4在用s1 s4; //s4是最后使用资源的对象所以需要释放s1[0] H;char rc s1[0];rc H;
}写时拷贝单线程底下没有问题但在多线程下可能会出错
~string(){//每次释放对象计数都要减一减完之后要看_count是不是0if (_str 0 -- *_pCount){delete[]_str;_str nullptr;delete _pCount;_pCount nullptr;}}线程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()