This is a trick worth knowing: nesting a struct in the private part of a class is a convenient way to give access to the struct to all the members of the class, but to deny access to everybody else (except, of course, friends of the class).
引用計數的思考過程:
① 針對: std::cout << s[1]; s[2] = 'a'; 這兩種情況無法分辨operator [] 是用作寫還是讀,提出 copy-on-write
② 針對: s1 = s; s2 = s; char* px = &s[0]; 如果px重新指派,s1, s2将都被改寫,提出增加一個share标志,
對于任何非const的operator[]操作,都将标志設為false,且無法恢複
幾個需要說明的地方:
RCObject::RCObject(const RCObject&)
: refCount(0), shareable(true) {}
這個refCount為0,因為這是一個“構造函數”,一個新對象的refCount當然是0了。
RCObject& RCObject::operator=(const RCObject&)
{ return *this; }
這沒有關于refCount的操作,因為這是“值”本身的相關操作,不是使用和封裝這個值的類
1.複制構造函數
String& String::operator=(const String& rhs)
{
if (value == rhs.value) { // do nothing if the values
return *this; // are already the same; this
} // subsumes the usual test of
// this against &rhs (see Item E17)
if (--value->refCount == 0) { // destroy *this's value if
delete value; // no one else is using it
}
value = rhs.value; // have *this share rhs's
++value->refCount; // value
return *this;
}
2.. 指針、引用與寫時拷貝
大部分情況下,寫時拷貝可以同時保證效率和正确性。隻有一個揮之不去的問題。看一下這樣的代碼:
String s1 = "Hello";
char *p = &s1[1];
char& String::operator[](int index)
{
if (value->refCount > 1) {
--value->refCount;
value = new StringValue(value->data);
}
value->shareable = false; // add this
return value->data[index];
}
引用計數的結構:
-
template<class T> // template class for smart class RCPtr { // pointers-to-T objects; T public: // must inherit from RCObject RCPtr(T* realPtr = 0); RCPtr(const RCPtr& rhs); ~RCPtr(); RCPtr& operator=(const RCPtr& rhs); T* operator->() const; T& operator*() const; private: T *pointee; void init(); }; class RCObject { // base class for reference- public: // counted objects void addReference(); void removeReference(); void markUnshareable(); bool isShareable() const; bool isShared() const; protected: RCObject(); RCObject(const RCObject& rhs); RCObject& operator=(const RCObject& rhs); virtual ~RCObject() = 0; private: int refCount; bool shareable; }; class String { // class to be used by public: // application developers String(const char *value = ""); const char& operator[](int index) const; char& operator[](int index); private: // class representing string values struct StringValue: public RCObject { char *data; StringValue(const char *initValue); StringValue(const StringValue& rhs); void init(const char *initValue); ~StringValue(); }; RCPtr<StringValue> value; };