本文主要是介绍String类的浅拷贝、深拷贝、引用计数、写时拷贝,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
皆以s2=s1为例浅拷贝:只是直接将s1的值拷贝过来,s1、s2共用同一块内存。
class String
{
public:String(const char* str):_str(new char[strlen(str) + 1]){strcpy(_str, str);}String(const String& s):_str(s._str){}String& operator=(const String& s){if (this != &s){_str = s._str;}return *this;}~String(){if (_str){cout << "delete" << endl;delete[] _str;}}private:char* _str;
};void TestString()
{String s1("bigbang");String s2(s1);String s3("12345");s3 = s1;
}
int main()
{TestString();system("pause");return 0;
}
缺陷是调用析构函数时一块内存会被多次释放,导致程序崩溃。
深拷贝:在拷贝构造时开辟了空间,s1、s2各占有一块内存,无论析构多少次程序都不会崩溃。
//深拷贝传统写法
class String
{
public:String(char* str = ""):_str(new char[strlen(str) + 1]){strcpy(_str, str);}String(const String& s):_str(new char[strlen(s._str) + 1]){strcpy(_str, s._str);} //String& operator=(const String& s) //缺陷:new开辟空间可能会失败,s1将会被破坏//{// if (this != &s)// {// delete[] _str;// _str = new char[strlen(s._str) + 1];// strcpy(_str, s._str);// }// return *this;//}String& operator=(const String& s) //解决了上述缺陷{if (this != &s){char* tmp = new char[strlen(s._str) + 1];strcpy(tmp, s._str);delete[] _str;_str = tmp;}return *this;}~String(){if (_str){cout << "delete" << endl;delete[] _str;_str = NULL;}}
private:char* _str;
};void TestString()
{String s1("bigbang");String s2(s1);
}
int main()
{TestString();system("pause");return 0;
}
//深拷贝现代写法:只在构造函数中new,只在析构函数中delete,可维护性变强
class String
{
public:String(char* str = ""):_str(new char[strlen(str) + 1]){strcpy(_str, str);}String(const String& s):_str(NULL){String tmp(s._str); //调用构造函数开辟临时空间,交换后可把原来的空间释放掉swap(_str, tmp._str);}String& operator=(const String& s){if (_str != s._str){String tmp(s);swap(_str, tmp._str);}return *this;}//String& operator=(String s) //针对已经存在的两个对象//{// swap(_str, s._str);// return *this;//}~String(){if (_str){cout << "delete" << endl;delete[] _str;_str = NULL;}}private:char* _str;
};void TestString()
{String s1("bigbang"); String s2(s1);String s3;s3 = s1;
}
int main()
{TestString();system("pause");return 0;
}
在引用计数中,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。
class String
{
public:String(char* str = ""):_str(new char[strlen(str) + 1]), _refCount(new int(1)){strcpy(_str, str);}String(const String& s):_str(s._str), _refCount(s._refCount){++(*_refCount);}String& operator=(const String& s){// 1.s1和s2是否指向同一块空间// 2.减减s1指向空间的引用计数,如s1是最后一块管理对象,则释放if (_str != s._str){this->Release();_str = s._str;_refCount = s._refCount;++(*_refCount);}return *this;}String& operator=(String s) //s是临时开辟出来的一块空间,出了函数会自动释放{swap(_str, s._str);swap(_refCount, s._refCount); //交换后引用计数不改变return *this;}~String(){Release();}void Release(){if (--(*_refCount) == 0){cout << "delete" << endl;delete[] _str;delete _refCount; //注意delete的格式和new的格式对齐}}
private:char* _str;int* _refCount;
};void TestString()
{String s1("bigbang");String s2(s1);String s3;s3 = s1;
}
int main()
{TestString();system("pause");return 0;
}
//引用计数的浅拷贝--现代写法+写时拷贝:指用浅拷贝的方法拷贝其他对象,多个指针指向同一块空间,
//只有当对其中一个对象修改时,才会开辟一个新的空间给这个对象,和它原来指向同一空间的对象不会受到影响。
class String
{
public:String(char* str = ""):_str(new char[strlen(str) + 1]), _refCount(new int(1)){strcpy(_str, str);}String(const String& s):_str(s._str), _refCount(s._refCount){++(*_refCount);}String& operator=(const String& s){if (_str != s._str){this->Release();_str = s._str;_refCount = s._refCount;++(*_refCount);}return *this;}String& operator=(String s){swap(_str, s._str);swap(_refCount, s._refCount);return *this;}void Release(){if (--(*_refCount) == 0){cout << "delete" << endl;delete[] _str;delete _refCount;}}~String(){Release();}char& operator[](size_t index){CopyOnWrite();assert(index < strlen(_str));return _str[index];}const char& operator[](size_t index) const{assert(index < strlen(_str));return _str[index];}void CopyOnWrite(){if (*_refCount > 1){char* tmp = new char[strlen(_str) + 1];strcpy(tmp, _str);--(*_refCount);_refCount = new int(1);_str = tmp;}}private:char* _str;int* _refCount;
};void Fun(const String& s)
{cout << s[4] << endl;
}
void TestString()
{String s1("bigbeng");String s2(s1);String s3 = s2;Fun(s1);s1[4] = 'a';cout << s1[4] << endl;
}
int main()
{TestString();system("pause");return 0;
}
这篇关于String类的浅拷贝、深拷贝、引用计数、写时拷贝的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!