本文讨论的焦点是一个对象的“可用状态”,从设计的角度看如何使用shared_ptr还是weak_ptr来考虑这个问题
这里所说的“对象可用”是指调用这个对象时是,安全的,数据是正确的,执行时能够实现对应的功能
而“对象不可用””是指调用这个对象时是,不安全的,不能保证数据的正确性,不能保证能够实现对应的功能
我们可以用“对象的生命/对象的是否存在(还活在内存中)”来表示对象的“可用状态”;当然我们可能也可以用其他方式来表示它的“可用状态”(后面有例子)
很多时候,我们可以选择用“对象的生命/对象的是否存在”来表示对象的“可用状态”, 因为这样的做法很多时候简单合理(尤其是函数指针时);
而且,“对象的生命/对象的是否存在”也是“对象可用状态”的必要非充分条件,
因为当对象不存在时,它也肯定就不可用了;这里“不可用”是指不能调用这个对象的属性或方法
而当对象仍存在时,依据设计,可能它早已不可用;这里“不可用”是指,如果仍去调用这个对象的属性或方法,不能完成原有功能,不能保证安全
如果我们选择用“对象的生命/对象的是否存在”来表示对象的“可用状态”
那么“对象的生命/对象的是否存在”就等价于它的“可用状态”,这时我们就应该慎用shared_ptr
当多个client使用shared_ptr来共享了一个对象时,“对象的生命/对象的是否存在”就被这些client平等地共享了
比如clientA, clientB使用一个相同的shared_ptr<Object> p
当clientA释放了p,而clientB没有释放p,p所指的对象不会被释放,这个对象还活着还存在 --> 那么就说明了这个对象还“可用”
也就是说,clientA和clientB共同决定了p所指的对象的可用状态,当任一个client不删它它就仍然可用
但是有时,从需求来说,并不是想让clientA和clientB共同来决定p所指的对象是否可用
有时只想让clientA来决定p所指的对象的可用状态,
而只有当p所指的对象仍然可用(仍然活着)时clientB才去使用这个对象,不希望clientB来决定p所指对象的可用状态
这时clientB就不应该使用shared_ptr,clientB用weak_ptr更合适
因为clientB需要的是一个“观察者”,clientB不应该享有“决定这个对象生命/可用状态的权利”
任何涉及“可用状态”的对象,当选择用“对象的生命/对象的是否存在”来表示对象的“可用状态”时,都应该仔细考虑这个问题
这里的p可以是函数对象,也可以是指向clientA,等等
如果涉及了多个对象,比如clientB使用functorA的一个函数对象,函数的参数又指向其他几个对象paramC,paramD,函数内部又使用其他函数对象functorE
那么每个使用对象的地方都应该考虑对象可用状态的问题
所以,clientB应该想到functorA和paramC,paramD的可用状态;functorA应该考虑到paramC,paramD和functorE的可用状态
===========================================================================================================
当然我们可能也可以用其他方式来表示它的“可用状态”,下面只是一种小例子
比如clientA可以调用clientB.subscribe(XXX, p)来把p传给clientB,XXX表示一个想订阅的东东
当clientA不再需要订阅时,再调用clientB.unsubscribe(XXX)
这时可以设计让clientB 默认unsubscribe后,p就不再可用了