在C++中的字符串有C语言继承过来的char* 型的,还有就是C++STL中的string型的了。
C++中的string类在实现的过程中会遇到一些特别的地方。
比如:深浅拷贝、写时拷贝、引用计数等一些概念
浅拷贝:
默认的拷贝构造函数(值拷贝)。会出现两个指针维护同一块空间的问题,可能会一个指针释放空间导致另一个指针访问非法空间。
深拷贝:
自己构造拷贝构造函数,即自己开辟新空间再用memcpy进行值拷贝,用指针维护新开辟的空间
写时拷贝:
在浅拷贝的基础上增加引用计数,若要修改同一块空间时,再开辟新空间并进行值拷贝
写时拷贝即实现operator[],缺点是用[]读的时候也进行拷贝
深浅拷贝的应用:
VS的string:用深拷贝实现。
Linux中的string:用带引用计数的浅拷贝实现,operator[]时进行写时拷贝
注:STL库中的string类有一个Buffer:
小于16个字符的string以空间换时间
大于16个字节的存在_ptr指针指向的另外空间
string类源码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cassert>
using namespace std;
//相同字符串指向同一块空间,用一个引用计数来统计该字符串被引用的次数,并且增加了写时拷贝
class String
{
friend ostream& operator<<(ostream& os, const String& s);
public:
//String()
// :_str(new char[1])
// , _refCount(new int(1));
//{
// _str[0] = '\0';
//}
String(const char *str = "") //默认字符串为空字符串
:_str(new char[strlen(str) + 1])
, _refCount(new int(1))
{
strcpy(_str, str);
cout << "String(const char *str)" << endl;
}
String(String& s) //拷贝构造函数
:_str(s._str)
, _refCount(s._refCount)
{
++(*_refCount);
}
//传统的写法(s1=s2)
String& operator=(const String& s)
{
//1、s1和s2指向同一块空间(不处理)
//2、减减s1指向空间的引用计数,若s1是最后一块管理对象,则释放s1
if (_str != s._str)
{
this->Release();
this->_str = s._str;
this->_refCount = s._refCount;
++(*_refCount);
}
return *this;
}
//现代的写法
String& operator=(String s) //拷贝s时引用计数已经加1
{
swap(_str, s._str);
swap(_refCount, s._refCount);
return *this;
}
void Release()
{
if (--(*_refCount) == 0)
{
cout << "delete" << endl;
delete[] _str;
delete _refCount;
}
}
//String* this
char& operator[](size_t index)
{
//写时拷贝
CopyOnWrite(); //缺点:读的时候也会进行拷贝
assert(index < strlen(_str));
return _str[index];
}
//const String* this
const char& operator[](size_t index) const //常成员函数,当访问常成员变量时调用
{
assert(index < strlen(_str));
return _str[index];
}
void CopyOnWrite()
{
//引用计数大于1时需要进行拷贝
if ((*_refCount)>1)
{
char* tmp = new char[strlen(_str) + 1];
strcpy(tmp, _str);
--(*_refCount);
_refCount = new int(1);
_str = tmp;
}
}
~String()
{
Release();
}
char* GetStr()
{
return _str;
}
private:
char* _str;
int* _refCount; //引用计数的指针
};
ostream& operator<<(ostream& os, const String& s) //重载string的输出符号
{
os << s._str;
return os;
}
int main()
{
const String str1("123456");
String str2="123";
String str3;
//str2 = str1;
str3 = str2;
String str4("abcdef");
String str5(str4);
cout << str1[3] << endl;
cout << str2 << endl;
cout << str3 << endl;
cout << str4 << endl;
cout << str5 << endl;
return 0;
}