C++ shared_ptr and circular references, what's the practice? 33

Posted by Brett Schuchert Sat, 25 Apr 2009 07:30:00 GMT

I’m looking for comments on the practice of using shared pointers in C++. I’m not actively working on C++ projects these days and I wonder if you’d be willing to give your experience using shared pointers, if any.

I’m porting one of our classes to C++ from Java (it’s already in C#). So to remove memory issues, I decided to use boost::shared_ptr. It worked fine until I ran a few tests that resulted in a circular reference between objects.

Specifically:
  • A book may have a receipt (this is a poor design, that’s part of the exercise).
  • A receipt may have a book.

Both sides of the relationship are 0..1. After creating a receipt, I end up with a circular reference between Receipt and Book.

In the existing Java and C# implementations, there was no cleanup code in the test teardown to handle what happens when the receipt goes away. This was not a problem since C# and Java garbage collection algorithms easily handle this situation.

Shared pointers, however, do not handle this at all. They are good, sure, but not as good as a generation-scavenging garbage collector (or whatever algorithms are used these days – I know the JVM for 1.6 sometimes uses the stack for dynamic allocation based on JIT, so it’s much more sophisticated than a simple generation-scavenger, right?)

OK, so how to fix this problem? One way I could do is is manually break the circularity:
boost::shared_ptr<Receipt> r = ...;
CHECK(xxx, yyy);
r.setCopy(boost::shared_ptr<Book>());

(I did not use these types like this. When I use templates, especially those in a namespace, I use typedefs and I even, gasp, use Hungarian-esque notation.)

That would work, though it is ugly. Also, it is error prone and will either require violating DRY or making an automatic variable a field.

I could have removed the back reference from the Receipt to the book. That’s OK, but is a redesign of a system deliberately written with problems (part of the assignment).

Maybe I could explicitly “return” the book, which could remove the receipt and the back-reference. That would make the test teardown a bit more complex (and sort of upgrade the test from a unit test to something closer to an integration test), but it makes some sense. The test validate borrowing a book, so to clean up, return the book.

Instead of any of these options, I decided to use a boost::weak_ptr on the Receipt side. (This is the “technology to the rescue solution”, thus my question, is this an OK approach.)

I did this since the lifetime of a book object is much longer than its receipt (you return your library books, right?). Also, the Receipt only exists on a book. But the book could exist indefinitely without a Receipt.

This fixed the problem right away. I got a clean run using CppUTest. All tests passed and no memory leaks.

Once I had the test working, I experimented. Why? The use of a weak_ptr exposes some underlying details that I didn’t like exposing. For example, this line of code:
aReceipt->getBook()->getIsbn();

(Yes, violating Law of Demeter, get over it, the alternative would make a bloated API on the Book class.)

Became instead:
aReceipt->getBook().lock()->getIsbn();

The lock() method promotes a weak_ptr to a shared_ptr for the life of the expression. In this case, it’s a temporary in that line of code.

This worked fine, but I decided to put that promotion into the Receipt class. So internally, the class stores weak_ptr, but when you ask the receipt for its book, it does the lock:
boost::shared_ptr<Book> getBook() {
    return book.lock();
}

On the one hand, anybody using the getBook() method is paying the price of the promotion. However, the weak_ptr doesn’t allow access to its payload without the promotion so it’s really required to be of any value. Or at least that’s my take on it.

Do you have different opinions?

Please keep in mind, this is example code we use in class to give students practice naming things like methods and variables and also practice cleaning up code by extracting methods and such.

Even so, what practice do you use, if any, when using shared_ptr? Do you use weak_ptr?

Thanks in advance for your comments. I’ll be reading and responding as they come up.

Comments

Leave a response

  1. Avatar
    Bruno Martínez about 6 hours later:

    weak_ptr is unnecessary most of the time. Use shared_ptr in one direction and raw object* in the other.

    Use weak_ptr when you need the automatic clearing of it’s value. This means you are actually checking for empty weak_ptrs and not just locking them assuming they are valid.

  2. Avatar
    Anna Nachesa about 15 hours later:

    I would have used the third object (“library” or something”) which would keep track of both books and receipts and which would return receipt(s) for a given book and a book for a given receipt. this way no circular reference seem to be needed, because both a book and a receipt would get these references from the “library”. Am I wrong?

  3. Avatar
    Brett L. Schuchert about 16 hours later:

    Bruno wrote:

    weak_ptr is unnecessary most of the time…
    I like the simplicity of that approach. Have you found it at all confusing to have the asymmetry? (Not that the alternative of using weak_ptr is symmetrical, clearly it is not.)

  4. Avatar
    Brett L. Schuchert about 16 hours later:

    Anna wrote:

    I would have used the third object (“library” or something”) which …

    This can certainly work. I wonder, however, does that make the library provide more lookups/cross references? If so, then it makes the library more of a (GoF) mediator and also possibly a bit of a bottleneck.

  5. Avatar
    Bruno Martínez about 21 hours later:

    It is asymetric. Classes have to be layered upfront. Usually this ordering is useful for other things, like knowing in which order to take mutex locks.

  6. Avatar
    M# 2 days later:

    Establish which object owns the other. If Book owns Receipt, it should use shared_ptr. Receipt could use a naked ptr to point back to it’s owner (the Book) or could use a weak_ptr. In C++ you must have clear object ownership, even when using smart ptrs.

  7. Avatar
    Washu 4 days later:

    This is primarily an ownership issue with shared_ptr. Specifically in C++ when you use a shared_ptr you are claiming that you own the object in question and will be responsible for cleanup, if necessary. By passing around shared_ptrs in this manner you can ensure that the object will be cleaned up.

    Using weak_ptr’s eliminates the ownership issue, but then requires some method of validation to ensure that the object still exists, hence why a promotion to shared_ptr is required.

    My usage of weak_ptr tends to be driven based on ownership of the object, and lifetime management. As an example, if I don’t need the object to be alive and can regenerate it when needed, a weak_ptr will be more appropriate than a shared_ptr.

  8. Avatar
    ????? ??? 2 months later:

    ??? ? ?? ??

  9. Avatar
    nike about 1 year later:

    Your article is write very well, I like it very much. mason0507 agew

  10. Avatar
    moncler about 1 year later:

    I decided to use a boost::weak_ptr on the Receipt side. (This is the “technology to the rescue solution”, thus my question, is this an OK approach.)

  11. Avatar
    Designer Bags about 1 year later:

    Awesome article!so many thanks.

  12. Avatar
    dan pompa about 1 year later:

    I think the important thing is that a team understand the naming convention. If different teams are calling things differently, then it is not that big a deal. I know I sometimes struggle with the naming – what is an acceptance test, can a functional test be an acceptance test? I like calling tests that are created in an iteration “acceptance tests” but they can be different types of tests – performance, security, functional, etc.

  13. Avatar
    Pandora about 1 year later:

    The replies were numerous and vociferous. Dave Astels poignantly stated that hand-rolling mocks is so 2001!

  14. Avatar
    willson about 1 year later:

    Thanks for sharing. I get satisfaction from this site. preserve it up. uggs outlet

  15. Avatar
    pandora about 1 year later:

    Beauty of purchasing on the internet is you can observe anything at all the particular provides, where in a store it may be challenging to kind on the other hand their products to uncover the right thing. Mums really like presents which are unique. Make an effort to current your current mother by using a reward which is personal, just as one case in point an engagement ring employing their identify etched within it. Gold jewelry create excellent gifts since they immortalize your current mom?¡¥s identify throughout gold. The rare metal pendant and a ring creates a great gifts for the mum, along with presents which are frequently disregarded .

  16. Avatar
    http://www.whiteiphone4transformer.com about 1 year later:

    Come and make a change for your lovely iphone 4 white!

  17. Avatar
    Silicone Molding about 1 year later:

    Intertech Machinery Inc. provides the most precise Plastic Injection Mold and Rubber Molds from Taiwan. With applying excellent unscrewing device in molds, Intertech is also very professional for making flip top Cap Molds in the world.

  18. Avatar
    moncler about 1 year later:

    thanks for Moncler Jackets || Christian louboutin UK || Moncler coats || Christian louboutin shoes || Christian louboutin pumps your post!

  19. Avatar
    lad about 1 year later:

    I love seeing websites that understand the value of providing a quality resource for free. It is the old what goes around comes around routine.

  20. Avatar
    ralph lauren over 2 years later:

    I’ve acquired a big amount of accomplishment & value participating best now there, however ‘m glad which could be not how you still sustain a completely new very best additional compared to brains. Some vendors prosper best now there, people in today finally not neighborhood a thing. Even fundamentally in all probability the most extraordinary items are generally buried with the great offer in only minutes.

  21. Avatar
    okey oyunu oyna over 2 years later:

    nice situation.

    internette görüntülü olarak okey oyunu oyna, gerçek kisilerle tanis, turnuva heyecanini yasa.

  22. Avatar
    cheap brand watches over 2 years later:

    It is really a nice post, it is always great reading such posts, this post is good in regards of both knowledge as well as information. Very fascinating read, thanks for sharing this post here.

  23. Avatar
    Monster Beats By Dr. Dre Studio over 2 years later:

    The Monster Beats By Dr. Dre Studio Headphones are classic shoes.You will be proud of owning them. Don’t hesitate!Take Monster Beats By Dr. Dre Solo Headphones home!

  24. Avatar
    christian louboutin shoes on sale over 2 years later:

    Have the christian louboutin patent leather pumps is a happy thing. Here have the most complete kinds of christian louboutin leather platform pumps.

  25. Avatar
    beats by dre store over 2 years later:

    high quality headphones new design headphones “We two have been 6. Yesterday a student was sick, I take a bus 930 back to school to see her, afraid of boring so far way to buy the basketball magazine, all the way t

  26. Avatar
    karin over 2 years later:

    I saw this one and fell in love! I must admit i was dubious about ordering a dress from a overseas company, but i can’t praise Lightinthebox enough for there professionalism, quality, communications, and swift delivery. I ordered a custom size and the dress was delivered in just over 2 weeks to the UK. One word sums up the quality of this dress… Wow!!! The material is really good quality and the craftsmanship is second to none

  27. Avatar
    Tips For Bowling over 2 years later:

    The balance of private good and general welfare is at the bottom of civilized morals; but the morals of the Heroic Age are founded on individuality, and on nothing else.

  28. Avatar
    ysbearing over 2 years later:

    Slewing bearing called slewing ring bearings, is a comprehensive load to bear a large

    bearing, can bear large axial, radial load and overturning moment.

  29. Avatar
    christian louboutin over 3 years later:

    Slewing bearing called slewing ring bearings, is a comprehensive load to bear a large

    bearing, can bear large axial, radial load and overturning moment.

  30. Avatar
    christian louboutin over 3 years later:

    Christian Louboutin Rolando Hidden-Platform Pumps Golden is a fashion statement – that’s sexy, it makes you look longer highlight, and it highlights the curves in the woman body and makes the body look more elegant and thinner without any diet.

    ?Brand: Christian Louboutin ?Material: Golden leather ?Specialty: Signature red sole ?Color: Golden ?Heel height: Approximately 130mm/ 5.2 inches high and a concealed 20mm/ 1 inch platform ?Condition: Brand New in box with dust bags & Original Box

    Fashion, delicate, luxurious Christian louboutins shoes on sale, one of its series is Christian Louboutin Rolando Pumps, is urbanism collocation. This Christian louboutins shoes design makes people new and refreshing. Red soles shoes is personality, your charm will be wonderful performance.

  31. Avatar
    moncler jassen over 3 years later:

    jaren ‘50 in de hoofdstad van Schotland Walker – Monestier p Clermont. De belangrijkste mode en stijl Moncler Moncler jassen kledingstuk kan worden, dat is heeft noodlijdende Die lezers niet Dat niveau van kwaliteit en stijl heeft. Nauwkeurig te zeggen, zeker uit de Moncler jas algemeen bekend staat om stijlvol gepresenteerd in feite snowboarden jassen., Dit Moncler doorgestikte onderscheiden Jumper is een van de ideale smaak besneeuwde dag. Net als de web design manager onder meer recht naar beneden zakken op de aarde, uw-eigen Moncler schildert ideale Resterende opwarmen in de goed vond fysieke verschi

  32. Avatar
    bladeless fans over 3 years later:

    C++ shared_ptr and circular references, what’s the practice? 31 good post29

  33. Avatar
    louboutin sales over 3 years later:

    C++ shared_ptr and circular references, what’s the practice? 32 hoo,good article!!I like the post!130

Comments