用String类模拟用 将“/0”拷贝进去:
将代码中的拷贝构造函数写完整后,程序就不崩溃了,此方法为深拷贝方法:
深拷贝最大的特点就是拷贝一个一模一样的空间,但是缺点是比较浪费空间。构造构对象越多,单独生成的空间就越多且都一样。从用户来看,数据从哪里来并不重要,然而浅拷贝会造成数据空间被释放多次。因此浅拷贝有浅拷贝的好,深拷贝有深拷贝的好!
引用空间就是给这个空间一个数代表这个空间目前有两个对象在使用,析构的时候就减少相应的次数,只要不是0就说明这个空间还有对象在用。
具体做法:
首先增加一个字符串引用计数器类:
// 增加字符串引用类;
// An highlighted block class String_rep { friend class String; friend ostream& operator<<(ostream &out, const String &s); public: String_rep(const char *str = '') :use_count(0) { m_data = new char[strlen(str) + 1]; strcpy(m_data, str); } String_rep(const String_rep &rep) :use_count(0) { m_data = new char[strlen(rep.m_data) + 1]; strcpy(m_data, rep.m_data); } String_rep& operator=(const String_rep &rep); ~String_rep() { delete[]m_data; m_data = nullptr; } public: void increment() { ++use_count; } void decrement() { if (--use_count == 0) { delete this; } } private: char *m_data; size_t use_count; };
现在的字符串类私有成员只包含一个字符串计数引用类:
但是析构的时候怎么析构?检查的时候会发现内存泄漏
因为new申请的空间都没释放。
对象要析构,就是减少引用计数。
问题:这个this是谁?
这个this就是当前对象s内部的指针m_rep,m_rep是String_rep类型,先调自己的析构方法,而它的析构方法是先释放空间:
**在此这里先释放m_data的空间(指针所指的资源),否则造成内存泄漏,也就是通过析构函数先回收资源,搞成空壳子之后再释放。**因此这里delete this先调用了String_rep自身的析构函数。
类里的东西属于静态的,它可以自己释放,new申请的叫动态的,需要手动释放(所谓动态内存管理)。
赋值操作怎么写?
就是说s2给s1赋值,呢就是说s1不在指向s,而是指向s2的空间,那么s的空间引用计数器就要减1,s2的空间引用计数器就要加1。
对于这种情况,拷贝构造的时候,因为是浅拷贝,指向相同的空间,就是将s1的内容修改后,那么势必会影响s对象的修改。
// 深拷贝与浅拷贝相关代码
// An highlighted block #include<iostream> #include<string.h> using namespace std; //引用计数器类 class String_rep { friend class String; friend ostream& operator<<(ostream &out, const String &s); public: String_rep(const char *str = '') :use_count(0) { m_data = new char[strlen(str) + 1]; strcpy(m_data, str); } String_rep(const String_rep &rep) :use_count(0) { m_data = new char[strlen(rep.m_data) + 1]; strcpy(m_data, rep.m_data); } String_rep& operator=(const String_rep &rep); ~String_rep() { delete[]m_data; m_data = nullptr; } public: void increment() { ++use_count; } void decrement() { if (--use_count == 0) { delete this; //自杀 } } private: char *m_data; size_t use_count; }; / class String { friend ostream& operator<<(ostream &out, const String &s); public: String(const char *str = '') :m_rep(new String_rep(str)) { m_rep->increment(); } String(const String &s) : m_rep(s.m_rep) { m_rep->increment();//增加引用计数 } String& operator=(const String &s) { if (this != &s) { m_rep->decrement(); m_rep = s.m_rep; m_rep->increment(); } return *this; } ~String() { m_rep->decrement();//减少引用计数 } public: //写时拷贝 void to_upper() { String_rep *new_rep = new String_rep(*m_rep); m_rep->decrement(); m_rep = new_rep; char *pch = m_rep->m_data; while (*pch != '\0') { if (*pch >= 'a' && *pch <= 'z') *pch -= 32; pch++; } m_rep->increment(); } private: String_rep *m_rep; }; ostream& operator<<(ostream &out, const String &s) { out << s.m_rep->m_data; return out; } void main() { String s1('abc'); String s2 = s1; cout << 's1 = ' << s1 << endl; cout << 's2 = ' << s2 << endl; s1.to_upper(); cout << 's1 = ' << s1 << endl; cout << 's2 = ' << s2 << endl; } /* void main() { //String t('xyz'); String s('abc'); String s1 = s; String s2('xyz'); s1 = s2; }
联系客服