文件String.h

  1#ifndef _STRING_H
  2#define _STRING_H
  3
  4class RefObject
  5{
  6public:
  7    RefObject();
  8    RefObject(const RefObject& rhs);
  9    RefObject& operator=(const RefObject& rhs);
 10    virtual ~RefObject() = 0;
 11
 12    void addRefCount();
 13    void delRefCount();
 14    bool isShared()const;
 15    bool isShareable()const;
 16    void markUnshareable();
 17    
 18private:
 19    int refCount;
 20    bool shareable;
 21}
;
 22
 23template<typename T>
 24class RCPtr
 25{
 26public:
 27    T* operator->()constreturn ptr;}
 28    T& operator*()constreturn *ptr;}
 29
 30    void init()
 31    {
 32        if(ptr == 0)return;
 33        if!ptr->isShareable() )ptr = new T( *ptr );
 34        ptr->addRefCount();
 35    }

 36
 37    RCPtr(T* pRaw):ptr( pRaw ){init();}
 38    RCPtr(const RCPtr& rhs):ptr(rhs.ptr){init();}
 39    ~RCPtr(){if(ptr)ptr->delRefCount();}
 40
 41    RCPtr& operator=(const RCPtr& rhs)
 42    {
 43        if( rhs.ptr == ptr ) return *this;
 44
 45        T* oldPtr = ptr;
 46        ptr =  rhs.ptr;    
 47        init();
 48        if(oldPtr)oldPtr->delRefCount();
 49        return *this;
 50    }

 51    RCPtr& operator=(T* pRaw)
 52    {
 53        if( ptr == pRaw ) return *this;
 54
 55        T* oldPtr = ptr;
 56        ptr =  pRaw;    
 57        init();
 58        if(oldPtr)oldPtr->delRefCount();
 59        return *this;
 60    }

 61private:
 62    T* ptr;
 63}
;
 64
 65class String
 66{
 67public:
 68    class CharProxy
 69    {
 70    public:
 71        CharProxy(String& rStr, int nPos):str(rStr), pos(nPos){}
 72        CharProxy& operator=(char c)
 73        {
 74            if( str.value->isShared() )
 75            {
 76                str.value = new StringValue( str.value->data );
 77            }

 78            str.value->data[pos] = c;
 79            return *this;
 80        }

 81        CharProxy& operator=(const CharProxy& rhs)
 82        {
 83            if( str.value->isShared() )
 84            {
 85                 str.value = new StringValue( rhs.str.value->data );
 86            }

 87            str.value->data[pos] = rhs.str.value->data[pos];
 88            return *this;
 89        }

 90
 91        //convert type of CharProxy to type of char to validate code like:char c = str[0]
 92        operator char(){return str.value->data[pos]; }
 93
 94        //const version of CharProxy to char conversion;
 95        operator const char()const{return str.value->data[pos]; }
 96
 97        //convert type of CharProxy to type of char& to validate code like:char& c = str[0];
 98        operator char&()
 99        {
100           if( str.value->isShared() )
101           {
102                str.value = new StringValue( str.value->data );
103           }

104           str.value->markUnshareable();
105           return str.value->data[pos]; 
106        }

107        //const version of conversion of CharProxy to char&;
108        operator const char&()const{return str.value->data[pos]; }
109        
110        //overload operator ampersand(&) to validate code like:char* p = &str[0];
111        char* operator&()
112        {
113           if( str.value->isShared() )
114           {
115                str.value->delRefCount();
116                str.value = new StringValue( str.value->data );
117           }

118           str.value->markUnshareable();
119           return &str.value->data[pos]; 
120        }

121        //const version of operator ampersand(&) overloading;
122        const char* operator&()constreturn &str.value->data[pos];}
123
124    private:
125        String& str;
126        int pos;
127    }
;
128
129    String(const char* cszStr = "");
130    //String(const String& rhs);
131    //String& operator=(const String& rhs);
132    ~String();
133    const char* c_str()const{return value->data;}
134
135public:
136    CharProxy operator[](size_t idx);
137    const CharProxy operator[](size_t idx)const;
138
139public:
140    struct StringValue:public RefObject
141    {
142        size_t len;
143        char* data;
144    
145        StringValue(const char* cszStr);
146        ~StringValue();
147    }
;
148
149private:
150    RCPtr<StringValue> value;
151}
;
152#endif
153

文件String.cpp

 1#include "String.h"
 2#include <string.h>
 3#include <assert.h>
 4
 5RefObject::RefObject():refCount(0),shareable(true){}
 6RefObject::RefObject(const RefObject& rhs):refCount(0),shareable(true){}
 7RefObject& RefObject::operator=(const RefObject& rhs){return *this;}
 8RefObject::~RefObject(){}
 9void RefObject::addRefCount(){++refCount;}
10void RefObject::delRefCount(){if(--refCount == 0 )delete this;}
11bool RefObject::isShared()const{return refCount > 1;}
12bool RefObject::isShareable()const{return shareable;}
13void RefObject::markUnshareable(){shareable = false;}
14
15String::String(const char* cszStr):value(new StringValue(cszStr))
16{             
17}

18
19String::~String()
20{
21}

22
23String::CharProxy String::operator[](size_t idx)
24{
25    assert( idx < value->len && idx >= 0);
26    return  String::CharProxy(*this, idx );    
27}

28const String::CharProxy String::operator[](size_t idx)const
29{
30    assert( idx < value->len && idx >= 0);
31    return CharProxy(const_cast<String&>(*this), idx );
32}

33
34String::StringValue::StringValue(const char* cszStr)
35{
36    len = strlen(cszStr);
37    data = new char[len + 1];
38    if( len == 0 )data[0= '\0';
39    else strcpy(data, cszStr);
40}

41
42String::StringValue::~StringValue()
43{
44    delete[] data;
45    data = 0;
46}

47

 

可能很奇怪,我们在所有的构造函数中都将refCount设为了0。这看起来违反直觉。确实,最少,构造这个RCObject对象的对象引用它!在它构造后,只需构造它的对象简单地将refCount设为1就可以了,所以我们没有将这个工作放入RCObject内部。这使得最终的代码看起来很简短。

另一个奇怪之处是拷贝构造函数也将refCount设为0,而不管被拷贝的RCObject对象的refCount的值。这是因为我们正在构造新的值对象,而这个新的值对象总是未被共享的,只被它的构造者引用。再一次,构造者负责将refCount设为正确的值。

RCObject的赋值运算看起来完全出乎意料:它没有做任何事情。这个函数不太可能被调用的。RCObject是基于引用计数来共享的值对象的基类,它不该被从一个赋给另外一个,而应该是拥有这个值的对象被从一个赋给另外一个。在我们这个设计里,我们不期望StringValue对象被从一个赋给另外一个,我们期望在赋值过程中只有String对象被涉及。在String参与的赋值语句中,StringValue的值没有发生变化,只是它的引用计数被修改了。

 

RCObject类给了我们一个存储引用计数的地方,并提供了成员函数供我们操作引用计数,但调用这些函数的动作还必须被手工加入其它类中。仍然需要在String的拷贝构造函数和赋值运算函数中调用StringValueaddReference removeReference函数。这很笨拙。我们想将这些调用也移入一个可重用的类中,以使得String这样的类的作者不用再担心引用计数的任何细节。能实现吗?C++支持这样的重用吗?

能。没有一个简单的方法将所有引用计数方面的工作从所有的类中移出来;但有一个方法可以从大部分类中将大部分工作移出来。(在一些类中,你可以消除所有引用计数方面的代码,但我们的String类不是其中之一。有一个成员函数搞坏了这件事,我希望你别吃惊,它是我们的老对头:非const版本的operator[]。别放心上,我们最终制服了这家伙。)

posted on 2010-07-14 20:26 mildcat 阅读(190) 评论(0)  编辑 收藏 引用 所属分类: C++

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理