Re: Why doesn't shared_ptr generate a cycle?
hzhuo1@gmail.com wrote:
Pete Becker wrote:
Creating a cycle is not an error. However, if you don't do something to
break the cycle, you get a resource leak. On the other hand, the code in
the message doesn't execute any destructors at all, so even if there
weren't a cycle there would be a resource leak.
I feel sorry that I didn't trigger the destructors in the main
function. This time I add a delete sentence to make the main function
look like the following:
int main(){
A *a= new A;
B *b= new B(a);
a->create(b);
delete a;
return 1;
}
When I execute the new program,it gives a pop-up message saying "Debug
assertion failed". Is it the expected error caused by the shared_ptr
cycle? And can this kind of error be corrected with weak_ptr?
This runtime error does not depend on the details of shared_ptr vs.
weak_ptr. The code deletes a; this runs A's destructor, which runs the
destructor for a's shared_ptr object, which deletes b; this runs B's
destructor, which runs the destructor for b's shared_ptr object, which
deletes a for the second time. You'd have the same problem if A and B
held raw pointers and their destructors just deleted the pointer.
But there's another important problem here: the code uses an A* in main
and a shared_ptr<A> in the B object to manage the same A object. That's
going to cause trouble. Use one or the other. If you need automatic
resource management, in general you shouldn't be messing with raw pointers.
A needs to be changed to handle a shared_ptr<B>:
class A
{
shared_ptr<B> x;
public:
void create(shared_ptr<B> bb) { x = bb; }
};
B needs to be changed to handle a shared_ptr<A>:
class B
{
shared_ptr<A> y;
public:
B(shared_ptr<A> aa) : y(aa) {};
};
and now we can change main to get back to something like your original code:
int main()
{
shared_ptr<A> a(new A);
shared_ptr<B> b(new B(a));
a->create(b);
return 0;
}
Now you've got a cycle: the destructors for the two shared_ptr objects
in main will run, but because the two resources each hold shared_ptr
objects pointing to the other, the new'ed resources won't be destroyed.
To break the cycle, one of the two links has to be something other than
a shared_ptr object. If you change B by changing the type of y from
shared_ptr<A> to weak_ptr<A> that will fix the problem. If you change B
by changing the type of y from shared_ptr<A> to A* that will also fix
the problem. For this example, either approach works fine. In more
complex situations, the choice depends on what else is going on with
resource management.
--
-- Pete
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]