Reputation: 10863
I have often had the desire to check to see if a shared_ptr
was the only owner of a shared object. It would be convenient for handing off behaviors before destroying the last shared_ptr, instead of having to do if after the destruction (my particular use case was dealing with preservation of weak pointers by rescuing them with another shared_ptr
before destruction. After destruction has started, it's too late to rescue them).
C++11[draft] 20.7.2.1.4:
For purposes of determining the presence of a data race, member functions shall access and modify only the shared_ptr and weak_ptr objects themselves and not objects they refer to. Changes in use_count() do not reflect modifications that can introduce data races.
This question clarified a concern I had had about p.use_count() == 1
causing a data race. However, I am still not convinced it is safe to use in the way I want to use it.
In a single-threaded world, if use_count()
returns 1, then you know you're the last owner of that object. In a multithreading world where you've avoided data races, it seems reasonable that use_count()
of 1 is sufficient to ensure you are the sole owner, but I'm having a frustrating time trying to get that from the spec-eese. I can't tell if there's some loophole that would permit a use_count of 1 even though another shared_ptr exists on another thread. On the other hand, it seems frustrating that the definition of use_count
might turn to goo just beacuse I handed a shared_ptr to another thread.
Can I ever get into a situation where use_count()
is 1, but I am not the only owner, by the rules of the spec? I recognize that, thanks to races, a use_count
of 2 does not explicitly mean I am sharing (the other thread might release my object after my call to use_count
on this thread), but I'm interested in the other direction, once I have seen use_count
of 1.
As a second related question: do the same rules apply for unique
, which seems to be custom tailored to my desired implementation, but does not have any extra statements made regarding thread safety?
Edit: In response to answers I've gotten, the situation I am interested in has the shared_ptr
we are calling unique_count
on is only accessible by a single thread, so I do not have to worry about any other thread successfully copying it... they have to find their own shared_ptr
to copy!
Upvotes: 1
Views: 131
Reputation: 303017
Absolutely. Even if it were specified that use_count()
and unique()
were both atomic, and it doesn't:
long use_count() const noexcept;
Returns: the number ofshared_ptr
objects,*this
included, that share ownership with*this
, or 0 when*this
is empty.
[ Note:use_count()
is not necessarily efficient.—end note ]
bool unique() const noexcept;
Returns:use_count() == 1
.
[ Note:unique()
may be faster thanuse_count()
. If you are usingunique()
to implement copy on write, do not rely on a specific value whenget() == nullptr
. —end note ]
There's nothing to stop something like this happening:
std::shared_ptr<Foo> sp;
// thread 1 // thread 2
bool uniq = sp.unique(); /**/
/**/ std::shared_ptr<Foo> cpy = sp;
if (uniq) { /**/
/* mine?? */ /**/ cpy->foo();
/* nope :-( */ /**/
} /**/
Upvotes: 0
Reputation: 218750
If there is a possibility that a weak_ptr
exists that points to the same control block as your single shared_ptr
, and if another thread might convert that weak_ptr
to a shared_ptr
, then your thread could observe a use_count() == 1
, but by the time it can do anything with that information, the other thread may construct a new shared_ptr
from the weak_ptr
, bumping the use_count
up to 2.
Even if there are no weak_ptr
s, if more than one thread has read access to your shared_ptr
(e.g. say its a global), then another thread might make a copy of it after you observe use_count() == 1
.
If your shared_ptr
is not accessible to any other thread, and there is no possibility that another thread might convert a weak_ptr
to a shared_ptr
, then use_count() == 1
is safe to depend on.
Upvotes: 4