Proxy模式設計——引用計數

談到C++的垃圾收集策略,有一個用的比較多的方法就是引用計數在引用計數中,每一個對象負責維護對象所有引用的計數值。當一個新的引用指向對象時,引用計數器就遞增,當去掉一個引用時,引用計數就遞減。當引用計數到零時,該對象就將釋放佔有的資源。
試想在某場景種,類A的資源在類B和類C中都被引用,因此如果A不在使用但是B和C還有用時,此時不能釋放A;而在釋放B和C時只需要消除對A的引用即可;只有當B和C都不再使用A的資源之後,A才能夠釋放。這樣一來,A,B和C在每次釋放的時候都需要檢查是否有依賴的引用關係,不僅編程麻煩,還降低了效率。
可以思考一下,是否有必要讓A知道誰在引用它,答案是沒必要,A只需要知道有多少個人在引用它,這樣A只需要維護一個計數器,每次添加新的引用時計數器加1,該資源釋放時計數器減1,當計數器數值爲0時就釋放A。
在實際設計代碼的時候,可以讓包含資源以及方法的類作爲內部類,然後在外部用一個含有“智能引用”的計數器以及指向資源的指針的類來封裝該類。這樣就可以實現一個簡單的含有引用計數功能、能夠智能收集垃圾的封裝類。一個實例代碼如下:
#include <iostream>
#include <cstring>

using namespace std;

//outer class
class String {
public:
    //default ctor
    String() {
        rep_ = new StringRep("");
        cout << "String ctor: (def):" << endl;
    }
    //1-arg
    String( const char* arg ) {
        rep_ = new StringRep(arg);
        cout << "String ctor: " << arg << "." << endl;
    }
    //copy ctor
    String( String & str) {
        //rep_ = new StringRep( *str.rep_ );
        rep_ = str.rep_;
        ++str.rep_->count_;
        cout << "String ctor (copy): " << str.rep_->str_ << "." << endl;
    }
    //dtor
    ~String() {
        cout << "String dtor: " << rep_->str_ << ", before decrement, count is " << rep_->count_ << endl;
        if(--rep_->count_ == 0)
            delete rep_;
    }
    String& operator= ( String &rhs ) {
        ++rhs.rep_->count_;
        if(--rep_->count_ == 0)
            delete rep_;
        rep_ = rhs.rep_;
        return *this;
    }
    friend ostream& operator << ( ostream&, String& );

    //inner class
    class StringRep {
    public:
        //make String a friend of StringRep
        friend class String;
        friend ostream& operator << ( ostream&, StringRep& );
        StringRep() {
            cout << "   StringRep ctor (def):" << endl;
            str_ = NULL;
            //initial count_
            count_ = 1;
        }
        StringRep( const char* in ) {
            cout << "   StringRep ctor: " << in << '.' << endl;
            str_ = new char[strlen(in) + 1];
            strcpy( str_, in );
            count_ = 1;
        }
        StringRep( StringRep& str ) {
            cout << "   StringRep ctor (copy): " << str.str_ << '.' << endl;
            str_ = new char[strlen(str.str_) + 1];
            strcpy( str_, str.str_ );
            count_ = str.count_;
        }
        ~StringRep() {
            cout << "   StringRep dtor: " << str_ << '.' << endl;
            delete str_;
        }
        StringRep& operator= ( StringRep& rhs ) {
            if (this == &rhs)  return *this;
            delete str_;
            str_ = new char[strlen(rhs.str_) + 1];
            strcpy( str_, rhs.str_ );
            return *this;
        }
        private:
        char*  str_;
        //add member data count_
        int count_;
    };

private:
    //a pointer to StringRep
    StringRep *rep_;
};

ostream& operator << ( ostream& os, String::StringRep& str ) { return os << str.str_; }
ostream& operator << ( ostream& os, String& str ) { return os << *(str.rep_); }

int main( void ) {
   String  a( "hello" );
   // String  b = "world"; is error in my computer
   String  b( "world" );
   String  c( a );
   String  d = a;
   String  e;
   a = b;
   e = b;
   cout << "a is " << a << '.' << endl;
   cout << "b is " << b << '.' << endl;
   cout << "c is " << c << '.' << endl;
   cout << "d is " << d << '.' << endl;
   cout << "e is " << e << '.' << endl;

   return 0;
}
編譯運行之後可以得到如下的結果:
//    StringRep ctor: hello.
// String ctor: hello.
//    StringRep ctor: world.
// String ctor: world.
// String ctor (copy): hello.
// String ctor (copy): hello.
//    StringRep ctor: .
// String ctor (def):
//    StringRep dtor: .
// a is world.
// b is world.
// c is hello.
// d is hello.
// e is world.
// String dtor: world, before decrement, count is 3
// String dtor: hello, before decrement, count is 2
// String dtor: hello, before decrement, count is 1
//    StringRep dtor: hello.
// String dtor: world, before decrement, count is 2
// String dtor: world, before decrement, count is 1
//    StringRep dtor: world.



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章