历史上的实现有多种,但基本上有三种方式:
-
Eager Copy(深拷贝)
-
COW(Copy-On-Write 写时复制)
-
SSO(Short String Optimization 短字符串优化)
以下是写时复制简单实现代码:
#include <string.h>
#include <iostream>
using std::cout;
using std::endl;
using std::ostream;
class CowString {
class CharProxy {
public:
CharProxy(CowString& self, int idx)
: _self(self)
, _idx(idx) {}
// 对于读操作,还可以给CharProxy类定义类型转换函数来进行处理
operator char() const {
return _self._pstr[_idx];
}
CharProxy& operator=(const CharProxy& rhs) {
_self._pstr[_idx] = rhs._self._pstr[rhs._idx];
return *this;
}
char& operator=(char ch);
// friend ostream& operator<<(ostream& os, const CharProxy& rhs);
private:
CowString& _self;
int _idx;
};
public:
CowString();
CowString(const CowString& rhs);
~CowString();
CowString(const char* pstr);
CowString& operator=(const CowString& rhs);
size_t size() {
return strlen(_pstr);
}
const char* c_str() const {
return _pstr;
}
int use_count() {
return *(int*)(_pstr - kRefcountLenth);
}
CharProxy operator[](int idx);
friend ostream& operator<<(ostream& os, const CowString& rhs);
// friend ostream& operator<<(ostream& os, const CharProxy& rhs);
private:
char* malloc(const char* pstr = nullptr) {
if (pstr) {
return new char[strlen(pstr) + 1 + kRefcountLenth]() + kRefcountLenth; // 申请后指针向后偏移
} else {
return new char[1 + kRefcountLenth]() + kRefcountLenth;
}
}
void release() {
decreaseRefcount();
if (use_count() == 0) {
delete[] (_pstr - kRefcountLenth);
_pstr = nullptr;
}
}
void initRefcount() {
*(int*)(_pstr - kRefcountLenth) = 1;
}
void increaseRefcount() {
++*(int*)(_pstr - kRefcountLenth);
}
void decreaseRefcount() {
--*(int*)(_pstr - kRefcountLenth);
}
private:
char* _pstr;
static const int kRefcountLenth = 4;
};
CowString::CowString()
: _pstr(malloc()) {
initRefcount();
}
CowString::CowString(const char* pstr)
: _pstr(malloc(pstr)) {
strcpy(_pstr, pstr);
initRefcount();
}
CowString::~CowString() {
release();
}
CowString::CowString(const CowString& rhs)
: _pstr(rhs._pstr) {
increaseRefcount();
}
ostream& operator<<(ostream& os, const CowString& rhs) {
os << rhs._pstr;
return os;
}
CowString& CowString::operator=(const CowString& rhs) {
if (this != &rhs) {
release();
_pstr = rhs._pstr;
increaseRefcount();
}
return *this;
}
CowString::CharProxy CowString::operator[](int idx) {
return CharProxy(*this, idx);
}
char& CowString::CharProxy::operator=(char ch) {
if (_idx >= 0 && _idx < _self.size()) {
if (_self.use_count() > 1) {
_self.decreaseRefcount();
char* ptmp = _self.malloc(_self._pstr);
strcpy(ptmp, _self._pstr);
_self._pstr = ptmp;
_self.initRefcount();
}
_self._pstr[_idx] = ch;
return _self._pstr[_idx];
} else {
cout << "out of range" << endl;
static char nullchar = '\0';
return nullchar;
}
}
#if 0
ostream& operator<<(ostream& os, const CowString::CharProxy& rhs) {
if (rhs._idx >= 0 && rhs._idx < rhs._self.size()) {
os << rhs._self._pstr[rhs._idx];
} else {
os << "out of range";
}
return os;
}
#endif
void test0() {
CowString str1("hello");
CowString str2 = str1;
cout << "str1:" << str1 << endl;
cout << "str2:" << str2 << endl;
cout << str1.use_count() << endl;
cout << str2.use_count() << endl;
cout << endl;
CowString str3;
str3 = str2;
str1[0] = 'H';
cout << str1[0] << endl;
str2[0] = str2[1];
cout << str2[0] << endl;
cout << "str1:" << str1 << endl;
cout << "str2:" << str2 << endl;
}
int main(void) {
test0();
return 0;
}