概念:在有些大型类中复制一个类要花费大量时间。
如
TString one("abcd");
TString two(one);
这时写时复制就可以解决这个问题,所有复制对象共用原对象,当要改变对象的数据成员时才产生一个新的副本。
.head
1 #pragma once 2 #include3 #include 4 #include 5 #include 6 using namespace std; 7 8 class TString 9 {10 public:11 //输入/输出操作符12 //构造函数,创建一个空字符对象13 TString();14 //创建一个字符串对象,该对象包含指向字符的s指针15 //s必须以NULL结尾,从s中复制字符16 TString(const char* s);17 //创建一个包含单个字符aChar的字符串18 TString(char aChar);19 TString(const TString& arg);//拷贝构造函数20 ~TString();//析构函数21 //赋值操作符22 TString& operator=(const TString& arg);23 TString& operator=(const char* s);24 TString& operator=(char aChar);25 //返回对象当前储存的字符个数26 int Size() const;27 //返回posn中len长度的子字符串28 TString operator()(unsigned posn, unsigned len) const;29 //返回下表为n的字符30 char operator()(unsigned n) const;31 //返回对下标为n的字符的引用32 const char& operator[](unsigned n) const;33 //返回指向内部数据的指针,当心34 const char* c_str()const { return _str; };35 //以下方法将修改原始对象。36 //把其他对象中的字符附加在*this后37 TString& operator+=(const TString& other);38 //在字符串中改动字符的情况39 TString& ToLower();//将大写字符转换成小写40 TString& ToUpper();//将小写字符转换成大写41 private:42 struct StringRep43 {44 char *_str;//实际的字符45 unsigned _refCount;//对它的引用的数目46 unsigned _length;//字符串中的字符数目47 };48 StringRep *_rp; //再TString中唯一的数据成员;49 50 };51 52 //支持TString类的非成员函数53 //返回一个新TSring类的对象,该对象为one和two的级联54 TString operator+(const TString& one, const TString& two);55 //输入/输出操作符56 ostream& operator<<(ostream& o, const TString& s);57 istream& operator >> (istream& stream, TString& s);58 //关系操作符,基于ASCII字符集比较。59 //如果两字符串对象包含相同的字符,则两对象相等。60 bool operator==(const TString& first, const TString& second);61 bool operator!=(const TString& first, const TString& second);62 bool operator<(const TString& first, const TString& second);63 bool operator>(const TString& first, const TString& second);64 bool operator>=(const TString& first, const TString& second);65 bool operator<=(const TString& first, const TString& second);
.cpp;
1 #include "TString.h" 2 3 4 5 TString::TString() 6 { 7 _rp = new StringRep; 8 _rp->_refCount = 1; 9 _rp->_length = 0; 10 _rp->_str = 0; 11 } 12 13 14 TString::TString(const char* s) 15 { 16 _rp = new StringRep; 17 _rp->_refCount = 1; 18 _rp->_length = strlen(s); 19 _rp->_str = new char[_rp->_length + 1]; 20 strcpy(_rp->_str, s); 21 } 22 23 TString::TString(char aChar) 24 { 25 _rp = new StringRep; 26 _rp->_refCount = 1; 27 _rp->_length = 1; 28 _rp->_str = new char[_rp->_length + 1]; 29 _rp->_str[0] = aChar; 30 _rp->_str[1] = 0; 31 } 32 33 34 TString::TString(const TString& other) 35 { 36 //这时重要的操作之一; 37 //我们需要再other中,通过_rp所指向的对象递增引用计数。它又获得一个引用。 38 other._rp->_refCount++; 39 //让它们共享资源 40 this->_rp = other._rp; 41 } 42 43 TString& TString::operator=(const TString& other) 44 { 45 if (this == &other) 46 return *this;//自我赋值 47 /*这时另一个重要的操作。我们需要再other中,通过_rp所指向的对象递增引用计数。 48 同时,需要用过this指向的对象递减引用计数*/ 49 other._rp->_refCount++; //它又获得一个引用 50 //递减和测试,是否仍然再使用它 51 if (--this->_rp->_refCount == 0) 52 { 53 delete[]this->_rp->_str; 54 delete this->_rp; 55 } 56 this->_rp = other._rp;//共享资源; 57 return *this; 58 59 } 60 61 62 63 //这是一个重要的成员函数,需要应用“写时复制”方案 64 TString& TString::ToLower() 65 { 66 char *p; 67 if (_rp->_refCount > 1) 68 { 69 //这是最困难的部分。分离TString对象并提供它的StringRep对象; 70 //这是“写时复制”操作 71 unsigned len = this->_rp->_length;//保存它 72 p = new char[len + 1]; 73 strcpy(p, this->_rp->_str); 74 this->_rp->_refCount--;//因为*this即将离开内存池; 75 this->_rp = new StringRep; 76 this->_rp->_refCount = 1; 77 this->_rp->_length = len; 78 this->_rp->_str = p;//p在前面已创建 79 } 80 81 //继续,并改变字符 82 p = this->_rp->_str; 83 if (p != 0) 84 { 85 while (*p) 86 { 87 *p = tolower(*p); 88 ++p; 89 } 90 } 91 return *this; 92 } 93 94 TString& TString::ToUpper()//和tolower的相似方法 95 { 96 return *this; 97 } 98 99 100 101 TString::~TString()102 {103 if (--_rp->_refCount == 0)104 {105 delete[] _rp->_str;106 delete _rp;107 }108 }109 110 //省略其他函数的实现;
思考:在上面的代码中,很多地方都需要创建、删除和操控StringRep对象。很明显,这并不是最好的方法。尝试修改实现,以便StringRep有自己的构造
函数、析构函数以及其他函数。这样,StringRep便可自我管理。另外,完成TString类的实现;