Boost logo

Boost Users :

Subject: Re: [Boost-users] Thread Safety of shared_ptr
From: Kevin Frey (kfrey_at_[hidden])
Date: 2011-05-03 00:57:59


> Whoa! ... This isn't how shared pointers works. You want:

> shared_ptr< Session > sp_Session = shared_ptr< Session >( new Session
);

No, I don't, actually. I have stated what I am doing. What I have not
stated is *why* I am doing it. I have deliberately not stated that
because I didn't want the discussion to go off on a tangent.

There is nothing wrong with having a dynamically allocated shared_ptr,
and no more or less wrong than having a dynamically allocated string or
vector or map. My shared_ptr is within a wrapper class and you are
basically implying that the only way I can use the shared_ptr is via
composition, not aggregation. I will agree that composition is the
preferred approach, but I can't do that, so my pseudo-code reflects
that. So at the risk of complicating the discussion even further, the
reason I *must* use aggregation is because the code in question is part
of a hybrid C++/CLI (.NET) implementation. A C++/CLI class *cannot* use
composition of a native type such as shared_ptr. So I *must* use
aggregation - that's just the way it is. But my question is about
boost::shared_ptr, and the context I am using it is irrelevant to my
question

So, having now let the cat out of the bag, here's the problem domain. My
.NET C++/CLI classes, which are garbage-collected, managed classes, have
ownership of native, unmanaged classes. I have three native classes A,
B, C, and three corresponding garbage-collected classes GA, GB, and GC.
The garbage-collected classes exist to allow my C++ classes to be used
from a .NET application without requiring a full rewrite of the native
C++ classes using a .NET language. For the uninitiated, .NET has a
concept called a finaliser which exists explicitly to clean up unmanaged
resources prior to garbage collection reclaiming the object. Garbage
collection is inherently non-deterministic in nature (ie. GC collected
object do not have a defined point where they go "out of scope" like
conventional C++), but my native classes have a dependency sequence
amongst them. In other words, my native objects can be classified as
Level 0, Level 1, and Level 2, such that all Level 2 objects must be
cleaned up before the Level 1 object on which it depends, and so on.
Since I cannot control the order of garbage collection, I must ensure
that the native parent objects do not get cleaned up before the child
objects. I am using shared_ptr to ensure the native objects are
destroyed at the correct time, irrespective of the order in which the
garbage-collected objects are destroyed.

Also, let's not get too hung up on the pseudo-code. It is *pseudo-code*.
It is to illustrate a point. My real code does not pass a reference to a
shared_ptr - it actually passes a reference to a containing object which
itself "owns" the shared_ptr, and gets it from that object. But there is
nothing fundamentally wrong with passing a reference to a shared_ptr. It
doesn't "completely defeat the purpose" at all. Why bother
constructing/destroying a temporary object? That's just inefficient.

I use shared_ptr when I have a situation where I don't know who is going
to be the last to clean-up an object, and I genuinely need to share the
same object.

The purpose of the question is to question the thread-safety aspects of
shared_ptr in the context of a simultaneous increment/decrement of the
ref counts by two different threads.

Nothing more, nothing less.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net