关于智能指针,引用计数的学习与实现

自从用过boost的智能指针:shared_ptr之后,一直对引用计数这种东西很好奇,想知道它是如何实现的,尤其是一个ptr改变了引用计数,如何能够即时的让其他的ptr知道;
曾经想过一些方法,比如说:对象之间是独立的,唯一能把各个对象之间联系到一起的就是类,那么就从类的静态成员上着手,于是我就想到了在静态成员变量上创建一个map:


static std::map<T*, int> ms_UseCountTable;


实现了一下,一测试,居然可行,着实兴奋了一下。。。
但是,这种方法有着非常明显的缺点:
1、这个map为静态;
2、就算是这么都没有的时候,也得维护一个空表;
3、每当有引用计数改变的时候,都得遍历一下这个表,将它找出来;
4、最致命的是!!!!————这个类是模板!!!——————也就是说,有多少个数据类型用到了智能指针,就得创建多少个表;
5、耦合度太高,完全绑在这个类上了,拿不下来;

基于以上几点考虑,像boost这种神级库,是不可能用这种挫法的。。。

之前在网上看过一篇文章,是讲std::string的,因为它为了效率用到了写时复制(copy-on-write),所以也用到了引用计数:

string str_a = "hellow"; 
string str_b = str_a;
str_b = "asdf"; //这时 str_a == “hellow”,str_b == “asdf”


如上所示:当创建str_b的时候,只是将str_a的引用计数加一,并没有在堆上再创建一份str_a的拷贝;而当要修改str_b的值时,检查其引用计数,如果大于一,就创建一份副本,如果等于一,则就直接修改它;

那么它的引用计数是存放在哪呢,答案是和字符串一起,放在堆上;

在堆上为字符串开辟内存的时候,故意多开辟4个字节,来存放引用计数:


// ..... char* p.......
int len = strlen(p);
m_p = new char[len + 4];
//.........


这样的话,所有指向 m_p 的string对象都会有一个共同的4字节来共享他们的引用计数,无论谁改变了它,其他人都会即时的知道;


有没有一种豁然开朗的感觉?哈哈~~~对啊,我们都知道,如果想共享一个东西,那么就都保留它的指针,只不过正好我们要共享的是一个数值,所以总是忘了这一点,想去保留值,而不是地址;
好了,原理已经理解了,下面就来实现它吧,再想想办法把它封装一下,如下:


class UseCount
{
public:
UseCount()
: m_pUseCount(new int(1))
{
}


UseCount(const UseCount& use)
: m_pUseCount(use.m_pUseCount)
{
++*m_pUseCount;
}


~UseCount()
{
Drop();
}


int GetCount() const
{
return *m_pUseCount;
}


bool Drop()
{
--*m_pUseCount;
if (IsEmpty())
{
delete m_pUseCount;
return true;
}
return false;
}


void Reset()
{
m_pUseCount = new int(1);
}


bool IsOnly() const 
{
return (*m_pUseCount == 1);
}


bool IsEmpty() const 
{
return (*m_pUseCount == 0);
}


bool Reattach(const UseCount& use)
{
bool bResult = false;
++*use.m_pUseCount;
if (Drop())
{
bResult = true;
}


m_pUseCount = use.m_pUseCount;
return bResult;
}


private:
int* m_pUseCount;
};



这样,引用计数这个类就完成了,想想看,这种方法相比一开始说的用静态成员变量来维护一个map的方法,是不是好了太多,上面所举的几个缺点,这里一个都没有,而且大大降低了耦合度:
它不仅可以用在通用的智能指针里,所有需要用到引用计数的地方都可以用它,包括刚才说到的string;


我是一个喜欢抽象的人,遇到任何一件事情,我都喜欢从中总结出来的什么,于是:


这个故事告诉了我们:如果你想共享一个东西,那么,没有什么比直接保存一个它的指针更好的方法了!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值