问题
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