Juce源码分析(八)强引用与弱引用

 一、何为强,何为弱?

       所谓强、弱只是相对而言的,强者制人而弱者受制于人。强引用控制着原对象的生和死,只要有一个强引用对象指向了原对象,那么原对象就不会被析构,当所有指向原对象的强引用都因为离开作用域而自然析构的时候,原对象的生命周期也就结束了,因为没有人能找到它了,理所当然,它的死期也就到了,这时强引用会通知编译器将他kill掉,否则,就会违背自然规律,发生内存泄露;而弱引用恰恰相反,弱引用所指向的原对象不但不受弱引用控制,所有弱引用的使用反而还受原对象的限制,弱引用并不对引用进行计数,而是当原对象析构时,发出通知,告诉所有弱引用,“你们都不要忙活了,你们的老窝已经没了“,这时弱引用依然存在,只是它们都成废物了,等着越过作用域这条”奈何桥“,也就彻底化为灰烬了,等待重生。这时我们看到了强引用的”专横跋扈“,掌握着生杀大权,同时也能够看到弱引用的”软弱无能“,任人宰割。这就是所谓的,软的(弱引用)怕硬的(源对象),硬的怕不要命的(强引用)。这样比喻是还是比较恰当,因为弱引用本身就生活在”栈“里,生死有命,又无权操作原对象,只能当原对象的傀儡;强引用虽然同样也是生活在”栈“中,但是在他们死的时候,会拉上原对象陪葬。


二、遇强则强

        强引用虽然可以控制原对象的生死,而自己却无法摆脱被析构的命运。天罗地网固然疏而不漏,但任何事物都会存在弱点,强引用在成千上万次的转世轮回中,终于悟出长生不老之术。于是,他就找了另外一个强引用作为合作”伙伴“,他让另外一个强引用躲进他所指向的对象中,而他自己躲入了这个强引用所指向的对象。这时奇迹便发生了,只要这两个强引用所指向的对象不析构,那么这两个强引用永远也不会析构,因为他们都是对象中的成员,反过来依然成立,只要这两个强引用不被析构,那么两个对象也不会析构,这时两个强引用发生了死锁,这两块内存永远也不会被释放,直到应用程序的结束。

class A: public ReferenceCountObject
{
public:

	ReferenceCountObjectPtr<B> m_b;

	JUCE_LEAK_DETECTOR(A)
};


class B: public ReferenceCountObject
{

		ReferenceCountObjectPtr<A> m_a;
		JUCE_LEAK_DETECTOR(B)
};




void main()
{
		ReferenceCountObjectPtr<A> a = new ReferenceCountObjectPtr<A>();
		ReferenceCountObjectPtr<B> b = new ReferenceCountObjectPtr<B>();
		a->m_b = b;
		b->m_a = a;

}

       比如以上程序 ,待程序运行完毕,会提示类A和类B分别有一个对象没有被回收。然而这并不是我们想要的,我们的最终目的是让他们符合自然规律,有生便会有死,如果放任他们“与天地同寿”,反而是没有必要的浪费,甚至发生危险。可以想象如果地球上的人只生不死的话,数年之后是什么后果。


三、强弱互补

       为了防止两个强引用“强强联手”,作为“造物者”,我们不能像上面那样,让两个强引用去结合。这时“百无一用”的弱引用遍派上了用场,强弱结合便不会发生死锁。

class Man: public ReferenceCountObject
{
public:

	WeakReference<Woman> myWife;                     //如果myWife所指向的Woman对象析构,myWife便不能再使用
	                                                                  //反之,Man对象析构,不会对myWife所指向的对象造成任何影响
	void DoHisWork()
	{

	}
	JUCE_LEAK_DETECTOR(Man)
};


class Woman: public ReferenceCountObject
{

	ReferenceCountObjectPtr<Man> myHasband;  //如果这个是Man的唯一引用,那么Wonman对象析构,Man也会随之析构,当然如果其他地方还有Man的引用,Man便不会析构
	                                                              //反之,如果Woman不析构,myHasband所指向的对象永远也不会析构
	WeakReference<Woman>::Master masterReference;
	friend class WeakReference<Woman>;

	void DoHerWork()
	{

	}
	JUCE_LEAK_DETECTOR(Woman)
};



ReferenceCountObjectPtr<Man> fun()
{
	ReferenceCountObjectPtr<Man> man = new ReferenceCountObjectPtr<Man>();
	ReferenceCountObjectPtr<Woman> woman = new ReferenceCountObjectPtr<Woman>();
	man->myWife = woman;
	woman->myHasband = man;



	woman->myHasband->DoHiswork();
	if (!man->myWife.wasObjectDeleted())
	{
		ReferenceCountObjectPtr<Woman> woman = man->myWife;  //这里注意弱引用不要直接使用,要转化为强引用
		woman->DoHerwork();                                                    //因为弱引用所指向的对象指不定什么时候被析构,转化为强引用,使用才安全
	}


	return man;
}

void main()
{
	ReferenceCountObjectPtr<Man> man = fun();
	if (!man->myWife.wasObjectDeleted())
	{
		ReferenceCountObjectPtr<Woman> woman = man->myWife;  //这里注意弱引用不要直接使用,要转化为强引用
		woman->DoHerwork();                                                    //因为弱引用所指向的对象指不定什么时候被析构,转化为强引用,使用才安全
	
	}else
	{
			printf("man->myWife已经析构");
	}
	
	ReferenceCountObjectPtr<Woman> woman2 = new ReferenceCountObjectPtr<Woman>();
	man->myWife = woman2;
	woman2->myHasband = man;

}
         这段代码,看起来比较乱,但是把它以故事的形式来读的话,反而更好理解。在函数fun()里,man和woman同时出生,然后“结婚”,结婚的约定是,woman保留man的强引用,man保留woman的弱引用,这样,有woman存在man不会死,而woman死时不会影响man,只会默默地留下遗言“我已经死了,不要想我了,你要好好活下去!”,反之,没有反之了,man不会比woman先死。于是他俩快乐的生活着,然而现实是残酷的,fun()函数只能有一个返回值,如果返回woman,那他俩都不会死,因为woman会带着man冲出fun()的作用域,如果返回man,那么woman就死定了,man保留的是woman的弱引用,没有能力将woman带出fun()函数。最后fun()函数将man返回,这时woman就不在了,于是man又和woman2“结婚”继续过完自己的一生。

        现实中我们讲究男女平等,但是在程序中要分清主次,两个类相结合的话,必然一主一次,孰强孰弱视情况而定。比如,root和node,item和list,都很好区分。








  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Skilla

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值