get count of std::weak_ptr objects tracking a shared resource

992 views
Skip to first unread message

write2r...@gmail.com

unread,
Dec 25, 2014, 3:16:33 AM12/25/14
to std-pr...@isocpp.org
It is useful to get the count of std::weak_ptr that are tracking a resource just as we have a reference count of std::shared_ptr that tracks a resource.

Most implementations already have this information but there is no API in the standards to extract this information.

I can explain why I need this information in one of the scenarios that I have in my project.

I have built a custom caching mechanism that does caching based on user request. The cached objects are disposed when the memory consumed by caching exceeds a pre-defined memory size set by the user. The cached objects are returned to the user  through  std::weak_ptr. The utility of the weak_ptr is primarily to avoid dangling pointers once the cache is cleared. However, the logic of which cache object has to be disposed is not a trivial decision and having a reference count of the number of weak_ptr is of immense value.


Thiago Macieira

unread,
Dec 25, 2014, 10:44:00 AM12/25/14
to std-pr...@isocpp.org
On Thursday 25 December 2014 00:16:32 write2r...@gmail.com wrote:
> It is useful to get the count of std::weak_ptr that are tracking a
> resource just as we have a reference count of std::shared_ptr that tracks a
> resource.

I dispute that. Besides for debugging, I don't see why an application would
need to know the count. Not to mention that any value you get is stale the
moment you got it, since weak_ptr is thread-safe and the atomic counter may
have changed values already.

The only thread-safe information is whether a given weak_ptr is the last
reference (i.e., count == 1).

> I have built a custom caching mechanism that does caching based on user
> request. The cached objects are disposed when the memory consumed by
> caching exceeds a pre-defined memory size set by the user. The cached
> objects are returned to the user through std::weak_ptr. The utility of
> the weak_ptr is primarily to avoid dangling pointers once the cache is
> cleared. However, the logic of which cache object has to be disposed is not
> a trivial decision and having a reference count of the number of weak_ptr
> is of immense value.

I think you're confounding your use-case with that of the weak_ptr. Your use-
case is valid, but your usage counts and even the age, "last use", etc., don't
belong in weak_ptr. For example, your cache could want to keep an item that
has been often requested, even though no one else is currently using it.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358

Ville Voutilainen

unread,
Dec 25, 2014, 11:38:10 AM12/25/14
to std-pr...@isocpp.org
On 25 December 2014 at 17:43, Thiago Macieira <thi...@macieira.org> wrote:
> On Thursday 25 December 2014 00:16:32 write2r...@gmail.com wrote:
>> It is useful to get the count of std::weak_ptr that are tracking a
>> resource just as we have a reference count of std::shared_ptr that tracks a
>> resource.
>
> I dispute that. Besides for debugging, I don't see why an application would
> need to know the count. Not to mention that any value you get is stale the
> moment you got it, since weak_ptr is thread-safe and the atomic counter may
> have changed values already.

Well, the use_count of a weak_ptr or a shared_ptr is across-thread
stale the moment it's returned, but that doesn't mean it's useless.
The use_count of a weak_ptr gives you the use_count of the underlying
shared state, not the shared_weak_count *that an implementation already
has*. I can easily imagine uses for exposing both of the counts, as can
apparently the original poster.


> The only thread-safe information is whether a given weak_ptr is the last
> reference (i.e., count == 1).

Sure, but the use cases for such things are far wider than across-thread
ones.

>> I have built a custom caching mechanism that does caching based on user
>> request. The cached objects are disposed when the memory consumed by
>> caching exceeds a pre-defined memory size set by the user. The cached
>> objects are returned to the user through std::weak_ptr. The utility of
>> the weak_ptr is primarily to avoid dangling pointers once the cache is
>> cleared. However, the logic of which cache object has to be disposed is not
>> a trivial decision and having a reference count of the number of weak_ptr
>> is of immense value.
> I think you're confounding your use-case with that of the weak_ptr. Your use-
> case is valid, but your usage counts and even the age, "last use", etc., don't
> belong in weak_ptr. For example, your cache could want to keep an item that
> has been often requested, even though no one else is currently using it.


Fair enough, but if they "don't belong in weak_ptr", how else would you
suggest such information to be exposed?

Miro Knejp

unread,
Dec 25, 2014, 12:59:48 PM12/25/14
to std-pr...@isocpp.org
On 25 December 2014 at 17:43, Thiago Macieira <thi...@macieira.org> wrote:
> The only thread-safe information is whether a given weak_ptr is the last
> reference (i.e., count == 1).
And not even that is reliable as new independent weak_ptr instances can
be created as long as a shared_ptr exists.

Thiago Macieira

unread,
Dec 25, 2014, 5:20:23 PM12/25/14
to std-pr...@isocpp.org
On Thursday 25 December 2014 18:38:08 Ville Voutilainen wrote:
> > I think you're confounding your use-case with that of the weak_ptr. Your
> > use- case is valid, but your usage counts and even the age, "last use",
> > etc., don't belong in weak_ptr. For example, your cache could want to
> > keep an item that has been often requested, even though no one else is
> > currently using it.
> Fair enough, but if they "don't belong in weak_ptr", how else would you
> suggest such information to be exposed?

Via composition. The cache is built around a structure that contains such
information and the object itself is one of the entries. The point being that
weak_ptr doesn't store a timestamp and I believe everyone would agree that it
never should, so I don't see why it should provide other information for
building a cache.

I wouldn't even use weak_ptr here, to be honest. It's not a cache if the
lifetime of the objects is not handled by the cache.

Thiago Macieira

unread,
Dec 25, 2014, 5:21:34 PM12/25/14
to std-pr...@isocpp.org
The "count == 1" part implies this is the last weak_ptr reference and there
are no shared_ptr references left.

Ramkumar Revanur

unread,
Dec 27, 2014, 11:46:30 PM12/27/14
to std-pr...@isocpp.org
"Not to mention that any value you get is stale the
moment you got it, since weak_ptr is thread-safe and the atomic counter may
have changed values already."

The use_count on a shared_ptr will be as stale as the "weak_count" if that was available. Does not mean it is not useful!

 

Ramkumar Revanur

unread,
Dec 28, 2014, 12:05:42 AM12/28/14
to std-pr...@isocpp.org

"Fair enough, but if they "don't belong in weak_ptr", how else would you 
suggest such information to be exposed? "


A function to return weak_count on shared_ptr is one approach.

Ramkumar Revanur

unread,
Dec 28, 2014, 12:07:47 AM12/28/14
to std-pr...@isocpp.org
Just as new shared_ptr can be created to the same resource from existing shared_ptr. The reliability of the "weak_count" is same as the reliability of use_count on a shared_ptr.

David Krauss

unread,
Dec 28, 2014, 1:30:02 AM12/28/14
to std-pr...@isocpp.org

> On 2014–12–28, at 1:07 PM, Ramkumar Revanur <write2r...@gmail.com> wrote:
>
> Just as new shared_ptr can be created to the same resource from existing shared_ptr. The reliability of the "weak_count" is same as the reliability of use_count on a shared_ptr.

A combination of use_count and weak_count is safer, though, because a potentially-last owner can check that there are no other potential owners on other threads. The weak count would need to be checked (evaluated) first though, which is a bit tricky with unordered expression evaluation semantics.

For that matter, a total reference_count which is the sum of strong and weak references would accomplish this more elegantly. It would be a drop-in replacement for use_count.

Applications that want to safely invalidate unsynchronized weak references need another new primitive, perhaps call it expire(), which atomically resets if unique. Then the caller can check whether the reset actually occurred. This is needed to make the design in the OP safe against a race between a cache eviction (or clearing) and a cache access.

Whether cache control is a valid use-case of weak_ptr, I’m not really sure. Why not? It’s unusual but clever. Control blocks introduce some inefficiency, but it sounds like a big shortcut and efficiency gain vs. shared_ptr alone.

Anyway, the proposed extensions won’t add any overhead, and there are surely other multithreaded applications out there with unsafe weak references.

David Krauss

unread,
Dec 28, 2014, 2:13:13 AM12/28/14
to std-pr...@isocpp.org

> On 2014–12–28, at 2:29 PM, David Krauss <pot...@gmail.com> wrote:
>
> Applications that want to safely invalidate unsynchronized weak references need another new primitive, perhaps call it expire(), which atomically resets if unique. Then the caller can check whether the reset actually occurred. This is needed to make the design in the OP safe against a race between a cache eviction (or clearing) and a cache access.

Eh, it’s not primitive. You can make a weak_pointer, reset the shared_ptr, and then reinitialize the shared_ptr from the weak_ptr.

ramkumar...@gmail.com

unread,
Dec 28, 2014, 3:09:39 AM12/28/14
to std-pr...@isocpp.org
I like the idea of sum of shared and weak count. Not sure if it can be a drop in replacement. Can be dangerous to existing code but did I misunderstand what you are suggesting ?

From what I have seen, it is easy to implement this in existing implementation on windows. I have to check if this is easy to implement in other std libraries.

Thiago Macieira

unread,
Dec 28, 2014, 9:01:36 AM12/28/14
to std-pr...@isocpp.org
On Sunday 28 December 2014 00:09:39 ramkumar...@gmail.com wrote:
> I like the idea of sum of shared and weak count. Not sure if it can be a
> drop in replacement. Can be dangerous to existing code but did I
> misunderstand what you are suggesting ?
>
> From what I have seen, it is easy to implement this in existing
> implementation on windows. I have to check if this is easy to implement in
> other std libraries.

A weak count or a total reference count are dangerous because one of the two
is not atomic. So not only would the value be stale by the time you got it, it
may also be fatally incorrect.

Imagine an implementation that keeps a separate strong count and a weak count.
When you ask for the total count, it needs to get both numbers and add them.
That's two operations and therefore not atomic. So it's possible that both
counts were 1 (two references) when the strong count was read, then the weak
reference was upgraded to a strong one, resulting in the weak count now being
zero and the function returning 1. That would imply the callee concludes it
has the only reference, which is incorrect.

It would be a similar situation if the implementation keeps a strong count and
a total count (such as the one I wrote for QSharedPointer). If you ask for the
weak count only, it needs to get the total count and subtract the number of
strong references. This is even worse, since the number of strong references
may have increased a lot between the two operations, so the weak count
function may return 1, zero or even negative numbers.

And I haven't heard a valid use-case for this yet. Though to be honest, I
don't know of a valid use-case for use_count() either, outside of debugging
and outside of a boolean "is it the only reference" condition.

Thiago Macieira

unread,
Dec 28, 2014, 9:03:06 AM12/28/14
to std-pr...@isocpp.org
Please see my other email about this.

This function is not only returning stale info, it may return *incorrect*
information. The only condition under which it would return correct info is
when you already know the information that it would return (that this is the
only reference).

Ramkumar Revanur

unread,
Dec 28, 2014, 10:12:07 AM12/28/14
to std-pr...@isocpp.org
Let us assume that it is not straight forward to implement total_count because the operation is not atomic. The total_count will require 2 operations as you have described. One operation to fetch the weak_count and another to add this count to strong_count. Irrespective of how you hold the information, there are 2 distinct operations that are to be performed. Therefore can't be easily implemented. ( Maybe with a critical section / volatile variables of some sort)

I am trying to understand the difficulties in implementation of weak_count instead (on say std::shared_ptr). I don't see why the implementation detail should not be similar to use_count on shared_ptr.

Further, I am not sure why you think the use case I have presented on caching not valid. You can choose to implement in your own way but I am not sure why if weak_count was available, this was not a valid use of it.

Ramkumar Revanur

unread,
Dec 28, 2014, 11:01:41 AM12/28/14
to std-pr...@isocpp.org
Look at the implementation of boost.


Boost has an implementation for weak_count!

template<class T, class VoidAllocator, class Deleter>
class weak_count { ... };

Thiago Macieira

unread,
Dec 28, 2014, 1:06:41 PM12/28/14
to std-pr...@isocpp.org
On Sunday 28 December 2014 07:12:07 Ramkumar Revanur wrote:
> Let us assume that it is not straight forward to implement total_count
> because the operation is not atomic. The total_count will require 2
> operations as you have described. One operation to fetch the weak_count and
> another to add this count to strong_count. Irrespective of how you hold the
> information, there are 2 distinct operations that are to be performed.
> Therefore can't be easily implemented. ( Maybe with a critical section /
> volatile variables of some sort)
>
> I am trying to understand the difficulties in implementation of weak_count
> instead (on say std::shared_ptr). I don't see why the implementation detail
> should not be similar to use_count on shared_ptr.

Like I said, it's one of the two. If the implementation holds a separate
strong and weak count, then implementing the weak count is trivial, but
implementing the total count is non-atomic. Alternatively, if the
implementation holds a strong count and a total count (like QSharedPointer
does), then implementing the weak count is non-atomic and, since it involves a
subtraction, it's even worse. However, it's easier to implement the pointers.

> Further, I am not sure why you think the use case I have presented on
> caching not valid. You can choose to implement in your own way but I am not
> sure why if weak_count was available, this was not a valid use of it.

Because either it doesn't work or I didn't understand it.

Your code held a weak_ptr to some object. That means it caches nothing, as the
data can be deleted outside of the cache's control. Any data that is still
accessible is being held alive by something else and therefore the cache,
again, does not control its lifetime.

Besides, what would you do with the number of weak references? You may have a
thousand users of the same weak_ptr object, but that's not relevant
information if the number of shared_ptr users is zero.

Maybe you wanted to get the weak count from a shared_ptr? That might make more
sense, but I still question it. So what if there are a thousand users? They
may simply want to be notified when the object gets deleted and they don't want
to influence its deletion -- that's why they're weak_ptr references instead of
shared_ptr ones.

If we go through with this, then I'd advise to go for the total count and
leave a big warning in the standard saying "in multithreaded applications, the
value returned by this function may be unreliable (more unreliable than
use_count); applications should not use this for anything except debugging".

Thiago Macieira

unread,
Dec 28, 2014, 1:12:38 PM12/28/14
to std-pr...@isocpp.org
On Sunday 28 December 2014 08:01:41 Ramkumar Revanur wrote:
> Look at the implementation of boost.
>
> http://www.boost.org/doc/libs/1_57_0/boost/interprocess/smart_ptr/detail/sha
> red_count.hpp
>
> Boost has an implementation for weak_count!
>
> template<class T, class VoidAllocator, class Deleter>
> class weak_count { ... };

I don't see it.

template<class T, class VoidAllocator, class Deleter>
class shared_count
{
[...]
long use_count() const // nothrow
{ return m_pi != 0? m_pi->use_count(): 0; }
[...]
};

template<class T, class VoidAllocator, class Deleter>
class weak_count
{
[...]
long use_count() const // nothrow
{ return m_pi != 0? m_pi->use_count() : 0; }
[...]
};

The two classes have the same implementation of use_count(). That means either
one of the two is broken or this weak_count class does not do what this mail
thread is asking for.

Howard Hinnant

unread,
Dec 28, 2014, 2:38:03 PM12/28/14
to std-pr...@isocpp.org
Informational:

The libc++ implementation would implement weak_count like so:

long
weak_count() const noexcept
{
return __shared_weak_owners_ + 1 - (use_count() > 0);
}

I.e. the “count of weak owners” is not strictly a count of weak_ptrs, nor is it a total count. All shared (strong) owners collectively count as a single weak owner.

Therefore, on this platform, neither weak_count() nor total_count() would be atomic if called via a weak_ptr. However if weak_count() is called via a shared_ptr, one could assume a preori (if the shared_ptr is not empty) that use_count() > 0, and therefore the result would be atomic. total_count() would still be non-atomic if called via a shared_ptr.

shared_ptr::use_count(); atomic
shared_ptr::weak_count(); atomic
shared_ptr::total_count(); not atomic

weak_ptr::use_count(); atomic
weak_ptr::weak_count(); not atomic
weak_ptr::total_count(); not atomic

Howard

Thiago Macieira

unread,
Dec 28, 2014, 5:40:04 PM12/28/14
to std-pr...@isocpp.org
On Sunday 28 December 2014 14:38:01 Howard Hinnant wrote:
> shared_ptr::use_count(); atomic
> shared_ptr::weak_count(); atomic
> shared_ptr::total_count(); not atomic
>
> weak_ptr::use_count(); atomic
> weak_ptr::weak_count(); not atomic
> weak_ptr::total_count(); not atomic

libstdc++'s implementation appears to be the same as libc++'s

For QSharedPointer's implementation:

use_count(): atomic
weak_count(): not atomic
total_count(): atomic

For all users.

It stands to reason someone may have implemented a std::shared_ptr/weak_ptr
similar to what I did for QSharedPointer. Therefore, it's not possible to
guarantee in the standard which of the operations would be atomic. In turn, if
we add the function, it needs to come with a big warning saying the result may
be incorrect if the application is multithreaded.

Ramkumar Revanur

unread,
Dec 29, 2014, 5:18:37 AM12/29/14
to std-pr...@isocpp.org
Let me explain the use case again but in more detail.

I have a caching library that is responsible for the lifetime of the cached objects. The cached objects may get populated from a database or a file. Sqlite, Mangodb, boost memory mapped file, use your imagination.

The lifetime of the cached object is influenced by one or more of the following 

1. time when the cached object was created
2. the frequency of accessing it
3. the time it was last accessed
4. the maximum cache size the user wants the library to create before some objects can be disposed
5 ...
(I think you get the picture)

The strategy for disposing a cached object could be a pattern decided by rules that best suits the user. Best to simplify by saying, the library should be smart to decide which cached objects should be disposed.
Because the library is expected to manage the lifetime of the cached objects, the user of the library in not in control of the lifetime of the cached object.

When the user wants to access the cached object, he fetches the cache object wrapped in a weak_ptr. He can lock this object within a scope to get hold of the shared_ptr. Within this scope, he will be guaranteed the validity of the cache object. The worst the library can do is to release the copy of shared_ptr it has but the reference count is not 0 as within the current scope, there is a strong owner that feeds the cache object to the user.

Now, there could be another process that could be writing to the cache source (database / file., etc). The caching library can either update those cached objects that are updated or decide to dispose them based on strategy that best suits the user. If the user decided to no longer user the cached object, he can inform the library that he is no longer using it or can simply drop the weak_ptr and the library will know that there is no active tracking pointer to the cached object and drop the object. Hope this explains the motivation to use weak_ptr and weak_count.

I am sure there are other ways of implementing it and so is the case for most problems.

Thiago Macieira

unread,
Dec 29, 2014, 8:09:33 AM12/29/14
to std-pr...@isocpp.org
On Monday 29 December 2014 02:18:37 Ramkumar Revanur wrote:
> When the user wants to access the cached object, he fetches the cache
> object wrapped in a weak_ptr. He can lock this object within a scope to get
> hold of the shared_ptr. Within this scope, he will be guaranteed the
> validity of the cache object. The worst the library can do is to release
> the copy of shared_ptr it has but the reference count is not 0 as within
> the current scope, there is a strong owner that feeds the cache object to
> the user.
>
> Now, there could be another process that could be writing to the cache
> source (database / file., etc). The caching library can either update those
> cached objects that are updated or decide to dispose them based on strategy
> that best suits the user. If the user decided to no longer user the cached
> object, he can inform the library that he is no longer using it or can
> simply drop the weak_ptr and the library will know that there is no active
> tracking pointer to the cached object and drop the object. Hope this
> explains the motivation to use weak_ptr and weak_count.

I find two problems with that API (this is IMO):

First, the cache manager should return a shared_ptr, not a weak_ptr, so the
user knows that the object she asked for didn't become invalid in the
microseconds between the asking and the converting to shared_ptr. If you have
an API that returns an explanation for the cache miss, then the cache hit
should be a shared_ptr. If, however, it indicates a cache miss by returning a
null pointer anyway, then this problem is minimised.

Second, since you can't forbid the upgrade to shared_ptr, the user can store
shared_ptr of your cached objects and negate your tracking of memory
consumption anyway. Moreover, the user should store weak_ptr when she wants to
declare "I don't care if this gets deleted". Your design calls for weak_ptr to
be used in the same role as shared_ptr, since it influences whether the object
gets deleted or not.

It sounds like you want an intermediate solution:
a) like shared_ptr, is used to make the decision to delete
b) like weak_ptr, cannot *stop* the deletion

Still IMO, you're abusing weak_ptr by using it in the way you described. The
Standard Library cannot be asked to do your job for you. Instead, you should
wrap the object and the pointer in your own class that accesses the internal
data where required. Your own class can then update an internal count of
active references. It can also update an internal age of how recently the
object has been used (the coarse monotonic timer on Linux costs little more
than one function call to obtain).

Therefore, since I find that a solution there is another solution that is a)
superior to the weak_ptr solution, b) doesn't abuse weak_ptr for what it
wasn't intended, and c) works even in multithreaded programs[*], I am still
discounting your scenario as valid.

[*] see Message-ID: <9595545.eDdFo9NLoN@tjmaciei-mobl4> for the conclusion
that weak_count would be not atomic in two of three scenarios and total_count
would also be not atomic in two of three scenarios.

Ramkumar Revanur

unread,
Dec 29, 2014, 11:31:09 AM12/29/14
to std-pr...@isocpp.org
IMO, you have not understood my use case on caching. But that is not the point of the discussion anyway. Difficulty to support function in a specific implementation is also not the discussion point.

The objective of this discussion is to get views of this *forum* on weak_count. If there is consensus, I can submit a patch to boost as a first step.

Ramkumar Revanur

unread,
Dec 29, 2014, 11:37:18 AM12/29/14
to std-pr...@isocpp.org

Thank you for this post. It does clear the air in terms of plausible atomic implementation on shared_ptr.

Thiago Macieira

unread,
Dec 29, 2014, 12:38:37 PM12/29/14
to std-pr...@isocpp.org
On Monday 29 December 2014 08:31:09 Ramkumar Revanur wrote:
> IMO, you have not understood my use case on caching. But that is not the
> point of the discussion anyway. Difficulty to support function in a
> specific implementation is also not the discussion point.
>
> The objective of this discussion is to get views of this *forum* on
> weak_count. If there is consensus, I can submit a patch to boost as a first
> step.

I disagree that the difficulty of implementing is not part of the discussion. I
think it's core to the discussion. If the function cannot return a reliable
and correct value, then it should not exist.

Douglas Boffey

unread,
Dec 29, 2014, 3:21:33 PM12/29/14
to std-pr...@isocpp.org
If there's a problem with atomicity, why not a function returning both
counts simultaneously?

Thiago Macieira

unread,
Dec 29, 2014, 11:14:42 PM12/29/14
to std-pr...@isocpp.org
On Monday 29 December 2014 20:21:31 Douglas Boffey wrote:
> If there's a problem with atomicity, why not a function returning both
> counts simultaneously?

Because that's still not atomic. It suffers from the exact same problem as I
described before. That still requires two load operations, which means the one
value loaded before might have changed by the time it got returned.

In other words having one function that returns a pair is no different than two
functions returning each an individual value.

Ramkumar Revanur

unread,
Dec 30, 2014, 12:45:04 AM12/30/14
to std-pr...@isocpp.org
The difficulty in a *specific* implementation. The operative word here is specific.

Douglas Boffey

unread,
Dec 30, 2014, 4:35:49 AM12/30/14
to std-pr...@isocpp.org
And I suppose wrapping it in a mutex is no go?
> --
>
> ---
> You received this message because you are subscribed to the Google Groups
> "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to std-proposal...@isocpp.org.
> To post to this group, send email to std-pr...@isocpp.org.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/.
>

Ramkumar Revanur

unread,
Dec 30, 2014, 7:09:03 AM12/30/14
to std-pr...@isocpp.org
There is no need for a mutex if the implementation can be atomic.

From the information presented in the thread

For QSharedPointer's implementation: 

use_count(): atomic 
weak_count(): not atomic 
total_count(): atomic

For LibstdC++ / libC++

shared_ptr::use_count();  atomic 
shared_ptr::weak_count();  atomic 
shared_ptr::total_count();  not atomic 

Now, for making a proposal we have to choose one of the approach for getting the weak_count and I am OK with weak_count or total_count

Thiago Macieira

unread,
Dec 30, 2014, 7:47:15 AM12/30/14
to std-pr...@isocpp.org
On Tuesday 30 December 2014 09:35:48 Douglas Boffey wrote:
> And I suppose wrapping it in a mutex is no go?

That would imply that all the operations that change those values need to be
wrapped in a mutex. So you're introducing a performance bottleneck for every
operation just for the ability to get the count.

Is it worth it?

Thiago Macieira

unread,
Dec 30, 2014, 7:48:48 AM12/30/14
to std-pr...@isocpp.org
On Tuesday 30 December 2014 04:09:03 Ramkumar Revanur wrote:
> There is no need for a mutex if the implementation can be atomic.
>
> From the information presented in the thread
>
> For QSharedPointer's implementation:
>
> use_count(): atomic
> weak_count(): not atomic
> total_count(): atomic
>
> For LibstdC++ / libC++
>
> shared_ptr::use_count(); atomic
> shared_ptr::weak_count(); atomic
> shared_ptr::total_count(); not atomic
>
> Now, for making a proposal we have to choose one of the approach for
> getting the weak_count and I am OK with weak_count or total_count

Whichever way you choose, there's a good chance that you're going to find an
existing implementation of shared_ptr that is not atomic and therefore the
resulting function is, at the very least, unreliable.

Thiago Macieira

unread,
Dec 30, 2014, 7:51:40 AM12/30/14
to std-pr...@isocpp.org
On Monday 29 December 2014 21:45:04 Ramkumar Revanur wrote:
> The difficulty in a *specific* implementation. The operative word here is
> specific.
>
> > I disagree that the difficulty of implementing is not part of the
> > discussion. I
> > think it's core to the discussion. If the function cannot return a
> > reliable
> > and correct value, then it should not exist.

I'm not sure what you're getting at.

Yes, a specific implementation makes it difficult to implement it. That means
there is at least one case out there under which the function would be
labelled "dangerous", which in turn means the standard should advise that it's
dangerous in all implementations so that few (if any) people ever use the
function.

What's the point of having a function in the standard that is "dangerous, may
return incorrect results"?

ramkumar...@gmail.com

unread,
Dec 30, 2014, 11:02:55 AM12/30/14
to std-pr...@isocpp.org
So you agree it is plausible to have an atomic implementation in stl. Right.

I understand it is *easy* to implement weak_count in few libraries but not straight forward in few others. That should not be a reason to prempt a proposal. Code can change and library implementation can be made coherent. We can patch the implementation that is incoherent to what approach we choose. I can volunteer if it helps. Afterall code is expected to change.

Thiago Macieira

unread,
Dec 30, 2014, 11:33:17 AM12/30/14
to std-pr...@isocpp.org
On Tuesday 30 December 2014 08:02:55 ramkumar...@gmail.com wrote:
> So you agree it is plausible to have an atomic implementation in stl. Right.

I agree it's plausible that some STL have implemented it in a way we could add
the function and it be atomic. But I am also saying that it's plausible that
there are two STL implementations that have incompatible requirements. That
means there's a very good chance that some implementations cannot do it
atomically.

> I understand it is *easy* to implement weak_count in few libraries but not
> straight forward in few others. That should not be a reason to prempt a
> proposal.

Yes, it should. It's not "uneasy" to implement a proper version in the others:
it's impossible. The value returned is unreliable in multithreaded
applications, period.

> Code can change and library implementation can be made coherent.
> We can patch the implementation that is incoherent to what approach we
> choose. I can volunteer if it helps. Afterall code is expected to change.

Only if the library breaks binary compatibility and that's a non-starter.

Ville Voutilainen

unread,
Dec 30, 2014, 11:45:45 AM12/30/14
to std-pr...@isocpp.org
On 30 December 2014 at 18:33, Thiago Macieira <thi...@macieira.org> wrote:
>> I understand it is *easy* to implement weak_count in few libraries but not
>> straight forward in few others. That should not be a reason to prempt a
>> proposal.
> Yes, it should. It's not "uneasy" to implement a proper version in the others:
> it's impossible. The value returned is unreliable in multithreaded
> applications, period.

That is, assuming that such applications don't employ external synchronization
on it, which they can choose to do.

>> Code can change and library implementation can be made coherent.
>> We can patch the implementation that is incoherent to what approach we
>> choose. I can volunteer if it helps. Afterall code is expected to change.
> Only if the library breaks binary compatibility and that's a non-starter.

A library implementation doesn't need to break binary compatibility to
make such changes. libstdc++ didn't when it made function signature changes
between c++03 and c++11.

Thiago Macieira

unread,
Dec 30, 2014, 12:07:08 PM12/30/14
to std-pr...@isocpp.org
On Tuesday 30 December 2014 18:45:43 Ville Voutilainen wrote:
> >> Code can change and library implementation can be made coherent.
> >> We can patch the implementation that is incoherent to what approach we
> >> choose. I can volunteer if it helps. Afterall code is expected to change.
> >
> > Only if the library breaks binary compatibility and that's a non-starter.
>
> A library implementation doesn't need to break binary compatibility to
> make such changes. libstdc++ didn't when it made function signature changes
> between c++03 and c++11.

I still don't know how that works. For all I know, it doesn't work.

In this case, just think of the following scenario:

- library A is built now and uses method 1 of reference-counting
- library B is built tomorrow and uses method 2 of reference-counting
- library A passes a shared_ptr object to library B, which holds a copy
- library B passes its own shared_ptr object to library A, which holds a copy

How will that work? How will library B know that it should use method 2
because the pointer came from library A? And moreover, how will library A,
which has no clue that method 2 even exists, use that method?

Remember, all of this is inlined. There are hardly any virtuals to be
overridden.

And finally, image that library B calls weak_count or total_count on all of its
pointers. How does it know which pointers are unreliable? How does the *user*
get told that the pointers are unreliable?

No, short of breaking the ABI and forcing the *whole* *world* to recompile,
this can't be done.

Ville Voutilainen

unread,
Dec 30, 2014, 12:19:11 PM12/30/14
to std-pr...@isocpp.org
On 30 December 2014 at 19:07, Thiago Macieira <thi...@macieira.org> wrote:
>> >> Code can change and library implementation can be made coherent.
>> >> We can patch the implementation that is incoherent to what approach we
>> >> choose. I can volunteer if it helps. Afterall code is expected to change.
>> > Only if the library breaks binary compatibility and that's a non-starter.
>> A library implementation doesn't need to break binary compatibility to
>> make such changes. libstdc++ didn't when it made function signature changes
>> between c++03 and c++11.
> I still don't know how that works. For all I know, it doesn't work.

For all I know, it does. I've tried it out with mixing the pre-C++11 cow
strings and C++11 non-cow strings with libstdc++.

> In this case, just think of the following scenario:
> - library A is built now and uses method 1 of reference-counting
> - library B is built tomorrow and uses method 2 of reference-counting
> - library A passes a shared_ptr object to library B, which holds a copy
> - library B passes its own shared_ptr object to library A, which holds a copy
> How will that work? How will library B know that it should use method 2
> because the pointer came from library A? And moreover, how will library A,
> which has no clue that method 2 even exists, use that method?

Library B knows which 'method' to use because the shared_ptr types are
not the same.
Library A cannot use the shared_ptr in Library B nor its 'method' because it's
not magically forward-compatible with future changes.

> And finally, image that library B calls weak_count or total_count on all of its
> pointers. How does it know which pointers are unreliable? How does the *user*
> get told that the pointers are unreliable?

Via a linker error, if the new function is attempted to be used on an
old type that
does not support it.

> No, short of breaking the ABI and forcing the *whole* *world* to recompile,
> this can't be done.

I doubt the correctness of that claim. There is practical evidence to
the contrary.

ramkumar...@gmail.com

unread,
Dec 30, 2014, 12:34:53 PM12/30/14
to std-pr...@isocpp.org

Some libraries take a lot of effort to make STL objects compatible. There is no agreed rules to maintain ABI across major releases of STL library that I know of. Please let us know what is that you follow. Some libraries (read MS VS) take major versions as an opportunity (and rightly so) to introduce changes that can break ABI.

For example:

x86 Container Sizes (Bytes)VC9 SP1VC9 SP1 
SCL=0
VC10VC11
vector<int>24161612
array<int, 5>20202020
deque<int>32322420
forward_list<int>N/AN/A84
list<int>2812128
priority_queue<int>28202016
queue<int>32322420
stack<int>32322420
pair<int, int>8888
tuple<int, int, int>16161612
map<int, int>3212168
multimap<int, int>3212168
set<int>3212168
multiset<int>3212168
hash_map<int, int>72444432
hash_multimap<int, int>72444432
hash_set<int>72444432
hash_multiset<int>72444432
unordered_map<int, int>72444432
unordered_multimap<int, int>72444432
unordered_set<int>72444432
unordered_multiset<int>72444432
string28282824
wstring28282824

I am sure there are few more breaking changes in Visual Studio 2013 and more so in Visual Studio 2015.

A nice article comes to my mind on rules of using STL (in MSVC?) written by Stephan T. Lavavej.

Thiago Macieira

unread,
Dec 30, 2014, 1:19:05 PM12/30/14
to std-pr...@isocpp.org
On Tuesday 30 December 2014 19:19:10 Ville Voutilainen wrote:
> > In this case, just think of the following scenario:
> > - library A is built now and uses method 1 of reference-counting
> > - library B is built tomorrow and uses method 2 of reference-counting
> > - library A passes a shared_ptr object to library B, which holds a copy
> > - library B passes its own shared_ptr object to library A, which holds a
> > copy How will that work? How will library B know that it should use
> > method 2 because the pointer came from library A? And moreover, how will
> > library A, which has no clue that method 2 even exists, use that method?
>
> Library B knows which 'method' to use because the shared_ptr types are
> not the same.

The types being different is a binary-incompatibility change of itself.
Moreover, keeping the name the same by way of an inline namespace introduces
linker or runtime errors instead of a source-incompatible error.

> Library A cannot use the shared_ptr in Library B nor its 'method' because
> it's not magically forward-compatible with future changes.

Exactly.

So imagine:

$ cat libA.h
#include <shared_ptr>

void method_in_lib_A(const std::shared_ptr<int> &);

Now imagine that lib B calls that method. Previously, it really was
"std::shared_ptr<int>". Now, after the standard-required changes, the Standard
Library implementation decides to use an inline namespace, so the type becomes
"std::__cxx17::shared_ptr<int>". Since the header didn't specify (and can't
specify!) the base version, this implies that the new build sees as the new
type.

As libA wasn't recompiled, this can result in a linker error (unresolved
symbol: method_in_lib_A(const std::shared_ptr<int> &)). Or, worse, a runtime
error, since we're talking about building another library and the default ELF
behaviour is to not resolve at link-time.

If we're talking about system libraries, libB getting updated implies updating
libA too, which implies updating everything that uses libA. As a cascade
effect, since now everything uses the new std::shared_ptr, now everything has
to be updated too.

> > No, short of breaking the ABI and forcing the *whole* *world* to
> > recompile,
> > this can't be done.
>
> I doubt the correctness of that claim. There is practical evidence to
> the contrary.

See above.

Thiago Macieira

unread,
Dec 30, 2014, 1:23:29 PM12/30/14
to std-pr...@isocpp.org
On Tuesday 30 December 2014 09:34:53 ramkumar...@gmail.com wrote:
> Some libraries take a lot of effort to make STL objects compatible. There
> is no agreed rules to maintain ABI across major releases of STL library
> that I know of. Please let us know what is that you follow. Some libraries
> (read MS VS) take major versions as an opportunity (and rightly so) to
> introduce changes that can break ABI.

Indeed, they do, which is a royal PITA for those of us trying to provide
binaries for MS compilers. Just see how many builds there are for Windows at
http://qt.io/download/ (click the option to show more). And that's not
including the different update versions -- just yesterday I was helping someone
who had downloaded the binary for MSVC 2013, but was using the wrong update
version (he had Update 3, the Qt binary was built with Update 4).

What's more, Microsoft recognised this as a problem and decided to change it
for 2015.

> I am sure there are few more breaking changes in Visual Studio 2013 and
> more so in Visual Studio 2015.
>
> A nice* article
> <http://www.reddit.com/r/cpp/comments/13zex3/can_vs2010_c_libsdlls_be_linked
> _into_a_vs2012_c/c78ott7>*comes to my mind on rules of using STL (in MSVC?)

See also:

http://blogs.msdn.com/b/vcblog/archive/2014/06/10/the-great-crt-refactoring.aspx
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4028.pdf

Anyway, Standard Libraries aren't required to keep compatibility.. But it
suffices that some want to, so any changes in the Standard that would require a
BC break need to be taken with great care. That's why I am saying that details
specific to an implementation are front and centre in this thread.

Ville Voutilainen

unread,
Dec 30, 2014, 1:48:46 PM12/30/14
to std-pr...@isocpp.org
On 30 December 2014 at 20:15, Thiago Macieira <thi...@macieira.org> wrote:
>> Library B knows which 'method' to use because the shared_ptr types are
>> not the same.
> The types being different is a binary-incompatibility change of itself.

Yes, but it's not an ABI break.

> Moreover, keeping the name the same by way of an inline namespace introduces
> linker or runtime errors instead of a source-incompatible error.

If it's done via inline namespaces, yes. If it's done with non-inline
namespaces,
then it's a source-incompatible error.

>> Library A cannot use the shared_ptr in Library B nor its 'method' because
>> it's not magically forward-compatible with future changes.
> Exactly.

And nobody imposed the type in B on A, so it's not going to break due
to B having
such a type. Such an incompatible type is not without a cost, but it
doesn't necessarily
lead to ABI breaks or recompiling the world.


> So imagine:
> $ cat libA.h
> #include <shared_ptr>
> void method_in_lib_A(const std::shared_ptr<int> &);
> Now imagine that lib B calls that method. Previously, it really was
> "std::shared_ptr<int>". Now, after the standard-required changes, the Standard
> Library implementation decides to use an inline namespace, so the type becomes
> "std::__cxx17::shared_ptr<int>". Since the header didn't specify (and can't
> specify!) the base version, this implies that the new build sees as the new
> type.

I fail to see the reason for the "can't specify"-part. The header can condition
the type it provides by default based on the C++ standard version used.

> As libA wasn't recompiled, this can result in a linker error (unresolved
> symbol: method_in_lib_A(const std::shared_ptr<int> &)). Or, worse, a runtime
> error, since we're talking about building another library and the default ELF
> behaviour is to not resolve at link-time.

Yeah, and there are ways to make it so it will just work.

> If we're talking about system libraries, libB getting updated implies updating
> libA too, which implies updating everything that uses libA. As a cascade
> effect, since now everything uses the new std::shared_ptr, now everything has
> to be updated too.

Old users of the old shared_ptr don't need to be updated, and don't need to
be recompiled.

Now, getting back to the original proposal:
1) I don't think its motivation is very strong
2) I don't think the atomicity argument is a deal-breaker
3) I'm not overly concerned about compatibility breaks
4) HOWEVER, concerning (3): I would certainly like to know whether
libc++, libstdc++ and Dinkumware/Microsoft already have a suitable shared_weak
count and whether the implementation of the proposal is just a matter
of exposing
what Howard outlined.

Without the survey in (4), I don't think the proposal should go
forward. The other
concerns become much more surmountable of (4) doesn't present problems.

Ramkumar Revanur

unread,
Dec 30, 2014, 2:16:34 PM12/30/14
to std-pr...@isocpp.org
On #1, Does it help if more scenarios where this can be used is presented.

On #4, I am happy to look in to MS implementation and get back.

Ville Voutilainen

unread,
Dec 30, 2014, 2:23:25 PM12/30/14
to std-pr...@isocpp.org
On 30 December 2014 at 21:16, Ramkumar Revanur <write2r...@gmail.com> wrote:
> On #1, Does it help if more scenarios where this can be used is presented.

Certainly. Good use cases always help illustrate the motivation of proposals.

> On #4, I am happy to look in to MS implementation and get back.

Cool.

Thiago Macieira

unread,
Dec 30, 2014, 7:12:22 PM12/30/14
to std-pr...@isocpp.org
On Tuesday 30 December 2014 20:48:44 Ville Voutilainen wrote:
> On 30 December 2014 at 20:15, Thiago Macieira <thi...@macieira.org> wrote:
> >> Library B knows which 'method' to use because the shared_ptr types are
> >> not the same.
> >
> > The types being different is a binary-incompatibility change of itself.
>
> Yes, but it's not an ABI break.

Not by itself. The ABI break happens when someone uses that type in their
function parameters. Now, the change of the type causes the functions to
change mangling, which is a BC break.

> > Moreover, keeping the name the same by way of an inline namespace
> > introduces linker or runtime errors instead of a source-incompatible
> > error.
>
> If it's done via inline namespaces, yes. If it's done with non-inline
> namespaces,
> then it's a source-incompatible error.

Indeed, and in my opinion it's better to trigger a source-incompatible error
than to hide a binary- or runtime-incompatible change behind a source-
compatible change.

> >> Library A cannot use the shared_ptr in Library B nor its 'method' because
> >> it's not magically forward-compatible with future changes.
> >
> > Exactly.
>
> And nobody imposed the type in B on A, so it's not going to break due
> to B having
> such a type. Such an incompatible type is not without a cost, but it
> doesn't necessarily
> lead to ABI breaks or recompiling the world.

I'm not sure what you mean.

> > So imagine:
> > $ cat libA.h
> > #include <shared_ptr>
> > void method_in_lib_A(const std::shared_ptr<int> &);
> > Now imagine that lib B calls that method. Previously, it really was
> > "std::shared_ptr<int>". Now, after the standard-required changes, the
> > Standard Library implementation decides to use an inline namespace, so
> > the type becomes "std::__cxx17::shared_ptr<int>". Since the header didn't
> > specify (and can't specify!) the base version, this implies that the new
> > build sees as the new type.
>
> I fail to see the reason for the "can't specify"-part. The header can
> condition the type it provides by default based on the C++ standard version
> used.

The point is that libA can't specify that it *wants* the C++11 version,
regardless of whether there's a future version available.

> > As libA wasn't recompiled, this can result in a linker error (unresolved
> > symbol: method_in_lib_A(const std::shared_ptr<int> &)). Or, worse, a
> > runtime error, since we're talking about building another library and the
> > default ELF behaviour is to not resolve at link-time.
>
> Yeah, and there are ways to make it so it will just work.

And for std::string in libc++, it looks like it's possible to make it work.
However, I don't see how the counters could change in shared_ptr without
triggering a full rebuild.

> > If we're talking about system libraries, libB getting updated implies
> > updating libA too, which implies updating everything that uses libA. As a
> > cascade effect, since now everything uses the new std::shared_ptr, now
> > everything has to be updated too.
>
> Old users of the old shared_ptr don't need to be updated, and don't need to
> be recompiled.

They do if they exchange shared_ptr with any library that has been updated.
That's the cascade effect.

> Now, getting back to the original proposal:
> 1) I don't think its motivation is very strong
> 2) I don't think the atomicity argument is a deal-breaker
> 3) I'm not overly concerned about compatibility breaks
> 4) HOWEVER, concerning (3): I would certainly like to know whether
> libc++, libstdc++ and Dinkumware/Microsoft already have a suitable
> shared_weak count and whether the implementation of the proposal is just a
> matter of exposing
> what Howard outlined.
>
> Without the survey in (4), I don't think the proposal should go
> forward. The other
> concerns become much more surmountable of (4) doesn't present problems.

That's fine by me. #3 is your opinion and we agree to disagree there.

Ville Voutilainen

unread,
Dec 30, 2014, 7:36:02 PM12/30/14
to std-pr...@isocpp.org
On 31 December 2014 at 02:12, Thiago Macieira <thi...@macieira.org> wrote:
>> > The types being different is a binary-incompatibility change of itself.
>> Yes, but it's not an ABI break.
> Not by itself. The ABI break happens when someone uses that type in their
> function parameters. Now, the change of the type causes the functions to
> change mangling, which is a BC break.

I can imagine ways to avoid changing such a parameter type change happening
without asking for it. See below.

>> > Moreover, keeping the name the same by way of an inline namespace
>> > introduces linker or runtime errors instead of a source-incompatible
>> > error.
>> If it's done via inline namespaces, yes. If it's done with non-inline
>> namespaces,
>> then it's a source-incompatible error.
> Indeed, and in my opinion it's better to trigger a source-incompatible error
> than to hide a binary- or runtime-incompatible change behind a source-
> compatible change.

No disagreement on that part.

>> >> Library A cannot use the shared_ptr in Library B nor its 'method' because
>> >> it's not magically forward-compatible with future changes.
>> > Exactly.
>> And nobody imposed the type in B on A, so it's not going to break due
>> to B having
>> such a type. Such an incompatible type is not without a cost, but it
>> doesn't necessarily
>> lead to ABI breaks or recompiling the world.
> I'm not sure what you mean.

I mean that using old-shared_ptr in A doesn't break just because B
decides to start
using a new-shared_ptr, IF the c++ library used continues to provide
both old and new.

>> > So imagine:
>> > $ cat libA.h
>> > #include <shared_ptr>
>> > void method_in_lib_A(const std::shared_ptr<int> &);
>> > Now imagine that lib B calls that method. Previously, it really was
>> > "std::shared_ptr<int>". Now, after the standard-required changes, the
>> > Standard Library implementation decides to use an inline namespace, so
>> > the type becomes "std::__cxx17::shared_ptr<int>". Since the header didn't
>> > specify (and can't specify!) the base version, this implies that the new
>> > build sees as the new type.
>> I fail to see the reason for the "can't specify"-part. The header can
>> condition the type it provides by default based on the C++ standard version
>> used.
> The point is that libA can't specify that it *wants* the C++11 version,
> regardless of whether there's a future version available.

I'm assuming it can, because I think there are ways to allow it to do so.

>> > As libA wasn't recompiled, this can result in a linker error (unresolved
>> > symbol: method_in_lib_A(const std::shared_ptr<int> &)). Or, worse, a
>> > runtime error, since we're talking about building another library and the
>> > default ELF behaviour is to not resolve at link-time.
>> Yeah, and there are ways to make it so it will just work.
> And for std::string in libc++, it looks like it's possible to make it work.
> However, I don't see how the counters could change in shared_ptr without
> triggering a full rebuild.

Well, for quite some time now I've been talking about solutions that add a new
shared_ptr rather than changing the counters in it.

>> > If we're talking about system libraries, libB getting updated implies
>> > updating libA too, which implies updating everything that uses libA. As a
>> > cascade effect, since now everything uses the new std::shared_ptr, now
>> > everything has to be updated too.
>> Old users of the old shared_ptr don't need to be updated, and don't need to
>> be recompiled.
> They do if they exchange shared_ptr with any library that has been updated.
> That's the cascade effect.

They do if they exchange a shared_ptr with any updated library and the multiple
shared_ptrs aren't versioned.

>> Now, getting back to the original proposal:
>> 1) I don't think its motivation is very strong
>> 2) I don't think the atomicity argument is a deal-breaker
>> 3) I'm not overly concerned about compatibility breaks
>> 4) HOWEVER, concerning (3): I would certainly like to know whether
>> libc++, libstdc++ and Dinkumware/Microsoft already have a suitable
>> shared_weak count and whether the implementation of the proposal is just a
>> matter of exposing
>> what Howard outlined.
>> Without the survey in (4), I don't think the proposal should go
>> forward. The other
>> concerns become much more surmountable of (4) doesn't present problems.
> That's fine by me. #3 is your opinion and we agree to disagree there.

Yeah, and I think our different day jobs cause certain differences in
our views on how important
(3) is or is not. :)

I should point out though that (1) plays a part in this. If this
proposal is likely to cause a true
ABI break, we must consider whether it's worth it. There are some
talks about an incompatible
new conceptified library, so perhaps the arrival of such a thing would
provide a more reasonable
time to make such changes than just adding small more-or-less breaking
changes here-and-there.
If this proposal were the only thing causing compatibility breaks, I
think I would seriously question
its motivation. Then again, I question its motivation even now - the
reason I'd be mildly for it is if
implementations can already easily expose this information, I don't
see the harm and can imagine
reasonable uses for it. That may end up being a very big if.

Ramkumar Revanur

unread,
Dec 30, 2014, 10:46:17 PM12/30/14
to std-pr...@isocpp.org

On #4,

In Microsoft STL, the changes are styled in bold. I don't see it as a breaking change either.

In file: memory

 // CLASS _Ref_count_base
class _Ref_count_base
 
{ // common code for reference counting
 
//....
 
private:
 _Atomic_counter_t _Uses
;
 _Atomic_counter_t _Weaks
;        

 
//....
public:
 
unsigned int _Get_uses() const
 
{ // return use count
 
return (_Get_atomic_count(_Uses));
 
}


 unsigned int _Get_weak_count() const
 
{ // return weak_count
 
return (_Get_atomic_count(_Weaks));
 
}



 
//....

 
//....



 
void _Incref()
 
{ // increment use count
 _MT_INCR
(_Ignored, _Uses);
 
}


 
void _Incwref()
 
{ // increment weak reference count
 _MT_INCR
(_Ignored, _Weaks);
 
}


 
void _Decref()
 
{ // decrement use count
 
if (_MT_DECR(_Ignored, _Uses) == 0)
 
{ // destroy managed resource, decrement weak reference count
 _Destroy
();
 _Decwref
();
 
}
 
}


 
void _Decwref()
 
{ // decrement weak reference count
 
if (_MT_DECR(_Ignored, _Weaks) == 0)
 _Delete_this
();
 
}


 
long _Use_count() const
 
{ // return use count
 
return (_Get_uses());
 
}


 
long _Weak_count() const
 
{ // return weak count
 
return (_Get_weak_count());
 
}



 
bool _Expired() const
 
{ // return true if _Uses == 0
 
return (_Get_uses() == 0);
 
}
 
//....

};



//...

//...

 
// TEMPLATE CLASS _Ptr_base
template<class _Ty>
 
class _Ptr_base
 
{
//...

//...

//...

 
long use_count() const _NOEXCEPT
 
{ // return use count
 
return (_Rep ? _Rep->_Use_count() : 0);
 
}


 long weak_count() const _NOEXCEPT
 
{ // return weak count
 
return (_Rep ? _Rep->_Weak_count() : 0);
 
}

//...

 
};

I am
in the process and building a few unit tests and stress testing it in concurrent usage scenarios.



Matthew Woehlke

unread,
Dec 31, 2014, 11:27:24 AM12/31/14
to std-pr...@isocpp.org
On 2014-12-30 19:36, Ville Voutilainen wrote:
> On 31 December 2014 at 02:12, Thiago Macieira wrote:
>> However, I don't see how the counters could change in shared_ptr without
>> triggering a full rebuild.
>
> Well, for quite some time now I've been talking about solutions that add a new
> shared_ptr rather than changing the counters in it.

FWIW, I don't see how this would help with the OP's use case. The point
would seem to be to continue to use std::shared_ptr / std::weak_ptr for
the benefit of external users that expect those. If the feature is added
to some new type, the OP might as well write their own pointer class
that has the necessary features, which can be done without a change to C++.

--
Matthew

Ville Voutilainen

unread,
Dec 31, 2014, 11:29:50 AM12/31/14
to std-pr...@isocpp.org
On 31 December 2014 at 18:27, Matthew Woehlke
The reason for adding a new shared_ptr would be to avoid ABI breaks.
If you don't
make such a change with a different type, you may end up having ABI breakage.
That's why I asked whether the existing implementations already have a suitable
count that they could return without incurring such breakage. The rest
of the sidetrack
was mostly a discussion about how to avoid ABI breaks, if any. If none, we have
much less of a problem.
Reply all
Reply to author
Forward
0 new messages