實現引用計數

實現代碼

#include "../head.h"
#include <memory>
#include <initializer_list>

class strBlob {
public:
    typedef vector<string>::size_type size_type;
    strBlob();
    strBlob(initializer_list<string> il);
    strBlob(const strBlob &sb);

    strBlob& operator=(const strBlob &rhs);

    size_type size() const {return data->size();}
    bool empty() const {return data->empty();}
    size_t get_use() {return *use;}
    void push_back(const string &t) {data->push_back(t);}

    void pop_back();
    string& front() const;
    string& back() const;

    ~strBlob();
private:
    vector<string> *data;
    void check(size_type i, const string &msg) const;
    size_t *use;
};



strBlob::strBlob() : 
    data(new vector<string>()), use(new size_t(1)) { }

strBlob::strBlob(initializer_list<string> il) :
    data(new vector<string>(il)), use(new size_t(1)) { }

strBlob::strBlob(const strBlob &sb) : 
    data(sb.data), use(sb.use) {++*use;}



strBlob& strBlob::operator=(const strBlob &rhs) {
    ++*rhs.use;
    if (--*use == 0) {
        delete data;
        delete use;
    }
    data = rhs.data;
    use = rhs.use;
    return *this;
}



void strBlob::check(size_type i, const string &msg) const {
    if (i >= data->size())
        throw out_of_range(msg);
}

void strBlob::pop_back() {
    check(0, "pop_back on empty strBlob");
    data->pop_back();
}

string& strBlob::front() const {
    check(0, "front on empty strBlob");
    return data->front();
}

string& strBlob::back() const {
    check(0, "back on empty strBlob");
    return data->back();
}



strBlob::~strBlob() {
    if (--*use == 0) {
        delete data;
        delete use;
    }
}



int main(int argc, char** argv) {
    strBlob a = {"hello", "world"};
    a.pop_back();
    strBlob b = a;
    b.push_back("fromb");
    cout << "The last word in a: " << a.back() << endl;
    cout << "The first word in b: " << b.front() << endl;

    strBlob c = b;
    cout << "After c = b; there are " << a.get_use() << " use from a now" << endl;

    c = {"ni", "hao"};
    cout << "After assign value to c, there are " << a.get_use() << " use from a now" << endl;
    return 0;
}

輸出

The last word in a: fromb
The first word in b: hello
After c = b; there are 3 use from a now
After assign value to c, there are 2 use from a now

這是從《C++ primer》13-27的習題引伸出來的代碼,將前文strBlob類給作了一些改編,使用這串代碼能夠直觀的感覺到引用計數的工做過程,他們能夠共享底層的數據,且實現了相似智能指針的效果,代碼的輸出也徹底符合預期函數

這裏重點關注的就是三個地方拷貝構造函數拷貝賦值運算符析構函數,要確保拷貝行爲的引用計數增減正確,析構時正確的釋放內存this

賦值語句

經過在成員函數中打印內容弄清楚了c = {"ni", "hao"};這條賦值語句工做的整個過程
1 賦值號右邊的內容經過使用列表構造函數生成了一個臨時的類的對象,此時它的引用計數爲一
2 臨時的類的對象經過拷貝賦值運算符給c賦值,此時進入到拷貝賦值運算符中指針

strBlob& strBlob::operator=(const strBlob &rhs) {
    ++*rhs.use;
    if (--*use == 0) {
        delete data;
        delete use;
    }
    data = rhs.data;
    use = rhs.use;
    return *this;
}
  • 此時臨時的類的對象就是rhs,它的引用計數加一,此時它的引用計數爲二
  • if (--*use == 0)這條判斷減減的use是對象a中的引用計數use,行爲相似於書中給shared_ptr賦予一個新值,計數器遞減
  • 而後就是把臨時的類的對象的數據成員所有賦值給c,包括對應的引用計數,依舊是二

3 到這裏整條賦值語句就已完成,接着就要把那個臨時的類的對象銷燬code

strBlob::~strBlob() {
    if (--*use == 0) {
        delete data;
        delete use;
    }
}
  • if (--*use == 0)這條判斷的use的值爲二,減減後變爲一,一切都如預料的那樣

因此,整條賦值語句完成後就正常的給c賦了新值,且它的引用計數爲一,對於它脫離了a的數據,a的引用計數也正常的減了一對象

相關文章
相關標籤/搜索