首页 > 代码库 > 【ThinkingInC++】63、引用计数

【ThinkingInC++】63、引用计数

/**
* 书本:【ThinkingInC++】
* 功能:引用计数,可以知道有多少个对象指向这个对象。
* 时间:2014年10月5日14:28:11
* 作者:cutter_point
*/

#include "../require.h" //这个文件是为了检验一些错误的,这个可以用#include<cassert>代替,但是相应的函数也要改
#include <string>
#include <iostream>

using namespace std;

class Dog
{
    //私有成员有string的名字,有引用的计数值,构造函数私有化,不让其他外部对象随便生成新的存储空间
    //operator=私有化,理由同上,不随便产生新的存储空间
    string nm;
    int refcount;   //用来计数,这个类的引用个数
    //这个是构造函数,初始化数据
    Dog(const string& name) : nm(name), refcount(1) {cout<<"Creating Dog: "<<*this<<endl;}
    //私有的operator=也是避免隐式调用构造函数
    Dog& operator = (const Dog& rv);
public:
    //然后创建一个Dog对象通过静态方法创建,就是在类开始的地方初始化
    static Dog* make(const string& name) {return new Dog(name);}
    //拷贝构造函数
    Dog(const Dog& d) : nm(d.nm+" copy"), refcount(1) {cout<<"Dog copy-constructor: "<<*this<<endl;}
    //析构函数
    ~Dog() {cout<<"Deleting Dog: "<<*this<<endl;}
    //用一个函数来增加一个Dog引用计数,attach
    void attach() {++refcount; cout<<"Attached Dog: "<<*this<<endl;}
    //一个函数减少引用计数
    void detach()
    {//减少一个对象引用
        require(refcount != 0);
        cout<<"Detaching Dog: "<<*this<<endl;
        //有条件地删除这个空间
        if(--refcount == 0)
            delete this;
    }

    //判定是否引用计数是否为1,就是意味着没有别的对象指向这块内存单元,然后返回this
    //如果大于1说明有别的对象指向这个内存单元,那么就复制这块内存单元,创建一个新的内存块
    Dog* unalias()
    {
        cout<<"Unaliasing Dog: "<<*this<<endl;
        //如果等于1,那么没有其他对象引用它,直接返回当前对象
        if(refcount == 1) return this;
        --refcount; //大于1那么就要把原来的对象复制出来一份新的存储空间

        return new Dog(*this);
    }
    //修改名字
    void rename(const string& newName)
    {
        nm=newName;
        cout<<"Dog renamed to: "<<*this<<endl;
    }
    //重载操作符<<输出流
    friend ostream& operator << (ostream& os, const Dog& d)
    {
        return os<<"["<<d.nm<<"], rc = "<<d.refcount;
    }
};

class DogHouse
{
    Dog* p; //一个指向Dog类的对象
    string houseName;
public:
    //构造函数,创建一个新的内存
    DogHouse(Dog* dog, const string& house) : p(dog), houseName(house) {cout<<"Created DogHouse: "<<*this<<endl;}
    //拷贝构造函数
    DogHouse(const DogHouse& dh) : p(dh.p), houseName("copy-constructed "+dh.houseName)
    {//用一个函数来增加一个Dog引用计数,attach
        //拷贝一次吧dh.p的指针赋值给p,没有创建新空间,就是增加了一个引用
        p->attach();
        cout<<"DogHouse copy-constructor: "<<*this<<endl;
    }
    //operator=的运算符重载
    DogHouse& operator=(const DogHouse& dh)
    {
        //operator=这里调用了赋值,创建了新的空间,会自动调用了构造函数
        //避免自赋值
        if(&dh != this)
        {
            houseName=dh.houseName+" = used";
            //所以这里构造函数的时候增加了一个引用在,减少引用,看是否最后一个,没有别的对象在使用它
            p->detach();
            p=dh.p; //传送指针,给这个对象增加一个引用对象
            p->attach();    //增加一个引用
        }

        cout<<"DogHouse operator= : "<<*this<<endl;
        return *this;
    }

    //析构函数,减少引用
    ~DogHouse()
    {
        cout<<"DogHouse destructor: "<<*this<<endl;
        p->detach();    //析构一个对象的时候调用这个析构,如果还有对象在引用就不回收空间,如果这是最后个直接回收空间
    }

    void renameHouse(const string& newName) {houseName=newName;}

    //判定是否引用计数是否为1,就是意味着没有别的对象指向这块内存单元,然后返回this
    //如果大于1说明有别的对象指向这个内存单元,那么就复制这块内存单元,创建一个新的内存块
    void unalias() {p=p->unalias();}
    void renameDog(const string& newName) {unalias(); p->rename(newName);}

    Dog* getDog() {unalias(); return p;}

    friend ostream& operator << (ostream& os, const DogHouse& dh)
    {
        return os<<"["<<dh.houseName<<"] contains "<<*dh.p;
    }
};

int main()
{
    DogHouse fidos(Dog::make("Fido"), "FidoHouse"), spots(Dog::make("Spot"), "SpotHouse");
    cout<<"开始构造函数"<<endl;
    DogHouse bobs(fidos);
    cout<<"拷贝构造函数之后"<<endl;
    cout<<"fidos:"<<fidos<<endl;
    cout<<"spots:"<<spots<<endl;
    cout<<"bobs:"<<bobs<<endl;
    cout<<"进入赋值运算 spots = fidos"<<endl;
    spots=fidos;
    cout<<"退出赋值运算 spots = fidos"<<endl;
    cout<<"spots:"<<spots<<endl;
    cout<<"进入自赋值"<<endl;
    bobs=bobs;
    cout<<"退出自赋值"<<endl;
    cout<<"bobs:"<<bobs<<endl;
    cout<<"开始改名字"<<endl;
    bobs.getDog()->rename("Bob");
    cout<<"退出改名"<<endl;

    return 0;
}




大部分注释都是直接写到代码上的,最近感觉自己越来越无知了和自大了!!! 赶紧去学习一下压压惊= =

吓死哥了。

【ThinkingInC++】63、引用计数