shared_ptr and logical pointer ownership use-case in a complex design

时光毁灭记忆、已成空白 提交于 2019-12-24 09:54:06

问题


I have an Object A that contains a shared resource (shared_ptr) r, A is the creator/owner of r upon construction the object "registers" its r with another object B. Object B holds a reference to A's r in a std::set. Object A is used as a Boost::asio::handler.

I need to unregister r from B when A is being destructed, and when A holds unique access to r, as A is r's creator it is responsible for destroying it. Note: A is copy constructed multiple times when it is used as an boost::asio handler. Holding unque acces here means that no asio operations are taking place (because if they were the reference count would be > 2, as copies were made of A).

At the moment unique access is testible by r.use_count() == 2 since A and B both have access to the object when no asynchronous operations are taking place. However, I do not find this test logically sensible.

I think I should change B's container from std::set<boost::shared_ptr<r> > to std:set<boost::weak_ptr<r> > so that r.unique() is logically true when no asynchronous operations are taking place. Is this a sensible use of a weak_ptr ?

The constructor and destructor of A (in_process_invoker) and the register(connect) and unregister(disconect) events look as follows in my code:

in_process_invoker(BackEnd & b_in)
  : client_data(new ClientData()),
    b(b_in),               
    notification_object(new notification_object_()) 
{
  b.connect(client_data);  
} 

~in_process_invoker()      
{
  if(client_data.unique()) 
  {
    b.disconect(client_data);       
  }

}

EDIT

I changed my design to use raw pointers, the default constructor marks the invoker as the primary invoker and copies of it as not-primary. When the primary is destroyed it frees up the memory.


回答1:


If you know for sure that the reference held by B will still be there when A performs the test of reference count, then why use any kind of smart pointer in B, why not a raw pointer? And if you don't know that B will still hold a reference then the current == 2 test isn't just non-sensible, it's incorrect.

The only advantage I see of a weak_ptr over a raw pointer is that if you change things in future so that A doesn't unregister with B, hence the reference might dangle, then a weak_ptr becomes useful to tell B what's happened. That might not even be possible depending how B uses r: if the design relies heavily on the fact that the reference is always valid then there's no point half-assing an attempt to cover the case that it isn't.

You could stick with shared_ptr everywhere, though, if A holds the reference to r via a shared_ptr to a proxy object, while B holds the reference with a shared_ptr directly to r. Then make it the responsibility of the proxy object to unregister from B. That way, the last copy of A to be destroyed will destroy the proxy, and the proxy will unregister with B and then destroy r. No need for anyone to check use_count.

A similar option is for B to hold a raw pointer, and have r unregister itself with B in its destructor. It might be harder to make that thread-safe, I'm not sure.

Ideally you'd use the "right" pointer type for the ownership semantics. If B co-owns r, then it should have a shared_ptr, so that r can safely outlive A. If B doesn't own r then use a weak_ptr if r might not be unregistered from B prior to destruction (and make sure B does the right thing when the weak_ptr has expired), or a raw pointer if B has a guarantee from someone else to ensure the validity of the pointer.




回答2:


It is not safe to mix smart and raw pointers. The whole point of using smart pointers is to have a way to manage object deallocation, and raw pointers undermine that, since there is no way to know whether a non-NULL raw pointer is valid or not.

Your solution using weak pointers seems sound to me --- it clearly distinguishes owning from non-owning references. I have made extensive use of this approach, where some object A is owned by one other object B, which holds it through a long-lived shared pointer, and the same object A is also referenced from any number of other objects C-Z through weak pointers. See my answer to a related question: shared_ptr: what's it used for



来源:https://stackoverflow.com/questions/7011877/shared-ptr-and-logical-pointer-ownership-use-case-in-a-complex-design

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!