C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Why doesn't shared_ptr generate a cycle?

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
hzhuo1@gmail.com
Guest





PostPosted: Tue Sep 19, 2006 12:14 am    Post subject: Why doesn't shared_ptr generate a cycle? Reply with quote



Consider the following code using boost::shared_ptr:
#include<iostream>
#include<boost/shared_ptr.hpp>
#include<boost/weak_ptr.hpp>
using namespace std;

class B;


class A{
private:
boost::shared_ptr<B> x;
public:
A();
void create(B* bb);
};

class B{
private:
boost::shared_ptr<A> y;
public:
B(A* aa){
y=boost::shared_ptr<A>(aa);
}
};

A::A(){ }

void A::create(B* bb){
x=boost::shared_ptr<B>(bb);
}

int main(){
A *a= new A;
B *b= new B(a);
a->create(b);

return 1;
}
In the main function , we create two dynamic objects *a and *b. *a
contains a shared_ptr<B> which points to *b, whereas *b contains a
shared_ptr<A> which points to *a. Before the main function returns ,it
should call A and B's destruction functions. But since A contains a
shared_ptr<B>,calling to A's destruction function will cause a call to
B's destruction function. Then it becomes a cycle.
I have run the above program in VC8.0 and it generates no errors.
It doesn't accord with my expectation. I wonder why.
Any explanations or opinions will be appreciated.

HaoZhuo


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Pete Becker
Guest





PostPosted: Tue Sep 19, 2006 1:13 am    Post subject: Re: Why doesn't shared_ptr generate a cycle? Reply with quote



hzhuo1 (AT) gmail (DOT) com wrote:
Quote:
In the main function , we create two dynamic objects *a and *b. *a
contains a shared_ptr<B> which points to *b, whereas *b contains a
shared_ptr<A> which points to *a. Before the main function returns ,it
should call A and B's destruction functions. But since A contains a
shared_ptr<B>,calling to A's destruction function will cause a call to
B's destruction function. Then it becomes a cycle.

Yup.

Quote:
I have run the above program in VC8.0 and it generates no errors.
It doesn't accord with my expectation. I wonder why.
Any explanations or opinions will be appreciated.

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.

--

-- 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! ]
Back to top
Thomas J. Gritzan
Guest





PostPosted: Tue Sep 19, 2006 1:13 am    Post subject: Re: Why doesn't shared_ptr generate a cycle? Reply with quote



hzhuo1 (AT) gmail (DOT) com schrieb:
[two objects, each one holds a shared_ptr of the other]
Quote:
In the main function , we create two dynamic objects *a and *b. *a
contains a shared_ptr<B> which points to *b, whereas *b contains a
shared_ptr<A> which points to *a. Before the main function returns ,it
should call A and B's destruction functions. But since A contains a
shared_ptr<B>,calling to A's destruction function will cause a call to
B's destruction function. Then it becomes a cycle.

There is a valid shared_ptr object to a in b, so a will never be
destroyed (the reference count won't drop to zero). There is a valid
shared_ptr in b to a, so b will never be destroyed. That's a cycle. And
two memory leaks.

Quote:
I have run the above program in VC8.0 and it generates no errors.
It doesn't accord with my expectation. I wonder why.
Any explanations or opinions will be appreciated.

Avoid cyclic references with shared_ptr. Think about your ownership
requirements. Use weak_ptr to break the cyclic references.

--
Thomas
http://www.netmeister.org/news/learn2quote.html

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Jens Theisen
Guest





PostPosted: Tue Sep 19, 2006 1:15 am    Post subject: Re: Why doesn't shared_ptr generate a cycle? Reply with quote

"hzhuo1 (AT) gmail (DOT) com" <hzhuo1 (AT) gmail (DOT) com> writes:

Quote:
Then it becomes a cycle.

I becomes a cycle, but there is no delete that could trigger
destruction.

What would you expect?

Jens

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
hzhuo1@gmail.com
Guest





PostPosted: Tue Sep 19, 2006 10:01 pm    Post subject: Re: Why doesn't shared_ptr generate a cycle? Reply with quote

Pete Becker wrote:

Quote:
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?

Thanks.

HaoZhuo


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
aa
Guest





PostPosted: Tue Sep 19, 2006 10:13 pm    Post subject: Re: Why doesn't shared_ptr generate a cycle? Reply with quote

Pete Becker wrote:
Quote:
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.

Sorry, but I don't get where the ref cycle should come from. If these
were intrusive_ptr, then ok, I'd see the cycle, but passing around
naked pointers and assign them to shared_ptr cannot generate cycles.
What am I missing here?


cheers,

aa


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Pete Becker
Guest





PostPosted: Tue Sep 19, 2006 11:10 pm    Post subject: Re: Why doesn't shared_ptr generate a cycle? Reply with quote

hzhuo1 (AT) gmail (DOT) com wrote:
Quote:
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! ]
Back to top
Pete Becker
Guest





PostPosted: Tue Sep 19, 2006 11:13 pm    Post subject: Re: Why doesn't shared_ptr generate a cycle? Reply with quote

aa wrote:
Quote:
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.

Sorry, but I don't get where the ref cycle should come from. If these
were intrusive_ptr, then ok, I'd see the cycle, but passing around
naked pointers and assign them to shared_ptr cannot generate cycles.
What am I missing here?


The call a->create(b) makes the cycle. The A object has a shared_ptr
object that points to the B object; the B object has a shared_ptr object
that points to the A object. Neither reference count will go to zero, so
the automatic resource management that you get from the use of
shared_ptr won't work.

--

-- 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! ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.