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