Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

shared_ptr id

42 views
Skip to first unread message

Norman J. Goldstein

unread,
Apr 12, 2015, 3:57:37 AM4/12/15
to
I would find it helpful for a shared_ptr to have an id() method, so that
two shared_ptr's manage the same object only if and only if they have
the same id's. If the managed object is not NULL, then the address of
the object can work as an id. Obviously, this does not work if the
object is NULL. An easy way to implement id(), for example, would be to
return the address of the location that stores the link count for the
shared_ptr.

Any thoughts on this?

Marcel Mueller

unread,
Apr 12, 2015, 4:20:06 AM4/12/15
to
On 12.04.15 09.57, Norman J. Goldstein wrote:
> I would find it helpful for a shared_ptr to have an id() method, so that
> two shared_ptr's manage the same object only if and only if they have
> the same id's. If the managed object is not NULL, then the address of
> the object can work as an id. Obviously, this does not work if the
> object is NULL.

Why not?

If a pointer does not point to an object then there is no definition of
"the same object".

And it is common practice and sometimes very useful that
reference-equals comparisons return true if both operands point to the
same object /or/ both are NULL.

> An easy way to implement id(), for example, would be to
> return the address of the location that stores the link count for the
> shared_ptr.
>
> Any thoughts on this?

Not recommended from my point of view.

#1 It is already possible to write x.get() == y.get() and the intention
of this comparison is obvious.

#2 Wrapping this by an id() function would allow to compare pointers of
incompatible type without an error.

#3 The data type of the id() cannot be safely int when sizeof(int) is
less than sizeof(X*).


Marcel

Paavo Helde

unread,
Apr 12, 2015, 7:57:31 AM4/12/15
to
"Norman J. Goldstein" <nor...@telus.net> wrote in news:mgd8gt$pil$1
@speranza.aioe.org:
This would not work if the link count is embedded in the linked object or
added to it via std::make_shared().

Also, conceptually I do not get why such a feature would be useful. A
smartpointer becomes NULL only if I assign NULL to it. Why should it then
remember to which object it pointed earlier? If I wanted to remember that,
I would not have assigned NULL to it in the first place.

Cheers
Paavo

Öö Tiib

unread,
Apr 12, 2015, 9:02:53 AM4/12/15
to
On Sunday, 12 April 2015 11:20:06 UTC+3, Marcel Mueller wrote:
> On 12.04.15 09.57, Norman J. Goldstein wrote:
> > I would find it helpful for a shared_ptr to have an id() method, so that
> > two shared_ptr's manage the same object only if and only if they have
> > the same id's. If the managed object is not NULL, then the address of
> > the object can work as an id. Obviously, this does not work if the
> > object is NULL.
>
> Why not?
>
> If a pointer does not point to an object then there is no definition of
> "the same object".
>
> And it is common practice and sometimes very useful that
> reference-equals comparisons return true if both operands point to the
> same object /or/ both are NULL.

Yes, that is common practice.

> > An easy way to implement id(), for example, would be to
> > return the address of the location that stores the link count for the
> > shared_ptr.
> >
> > Any thoughts on this?
>
> Not recommended from my point of view.
>
> #1 It is already possible to write x.get() == y.get() and the intention
> of this comparison is obvious.
>
> #2 Wrapping this by an id() function would allow to compare pointers of
> incompatible type without an error.

It may be desirable to compare smart pointers of incompatible type
to find out if they do (or do not) alias to same most derived object.
The expression above does not compile on case where 'x' is
'std::shared_ptr<base_1>' and 'y' is 'std::shared_ptr<base_2>'
and 'base_1' and 'base_2' are unrelated base classes. The
'x' and 'y' may actually use same reference counter if there is
multiple inheritance. To resolve the issue we can write:

dynamic_cast<void*>(x.get()) == dynamic_cast<void*>(y.get())

However that looks ugly (can be mitigated with inline function)
requires RTTI and is likely less efficient than to compare addresses
of reference counter if any. Both efficiency difference and the
ugliness grow when at least one is 'weak_ptr'.

> #3 The data type of the id() cannot be safely int when sizeof(int) is
> less than sizeof(X*).

Why it must be 'int'? To me it seems that OP clearly wrote that his
simplest implementation returns address of reference count. Reference
count is 'long' by C++ standard, Address to it is 'long*'. So 'id()'
can return 'void const*' or 'intptr_t'.

Öö Tiib

unread,
Apr 12, 2015, 9:30:09 AM4/12/15
to
On Sunday, 12 April 2015 14:57:31 UTC+3, Paavo Helde wrote:
> "Norman J. Goldstein" <nor...@telus.net> wrote in news:mgd8gt$pil$1
> @speranza.aioe.org:
>
> > I would find it helpful for a shared_ptr to have an id() method, so that
> > two shared_ptr's manage the same object only if and only if they have
> > the same id's. If the managed object is not NULL, then the address of
> > the object can work as an id. Obviously, this does not work if the
> > object is NULL. An easy way to implement id(), for example, would be to
> > return the address of the location that stores the link count for the
> > shared_ptr.
>
> This would not work if the link count is embedded in the linked object or
> added to it via std::make_shared().

Why it won't work? The reference count of 'shared_ptr' (and 'weak_ptr')
must be 'long int' regardless of where it is stored. Its address can't
move around in memory during life-time of referenced object.

> Also, conceptually I do not get why such a feature would be useful. A
> smartpointer becomes NULL only if I assign NULL to it. Why should it then
> remember to which object it pointed earlier? If I wanted to remember that,
> I would not have assigned NULL to it in the first place.

Maybe what he wants is something achievable with
'std::shared_ptr::owner_before' or 'std::shared_ptr::owner_less'. He did
not describe it too well.

Norman J. Goldstein

unread,
Apr 12, 2015, 1:03:44 PM4/12/15
to
Thanks for all the responses. I will address all the comments and
clarify, further.

On Sunday, 12 April 2015 11:20:06 UTC+3, Marcel Mueller wrote:
> On 12.04.15 09.57, Norman J. Goldstein wrote:
>> I would find it helpful for a shared_ptr to have an id() method, so that
>> two shared_ptr's manage the same object only if and only if they have
>> the same id's. If the managed object is not NULL, then the address of
>> the object can work as an id. Obviously, this does not work if the
>> object is NULL.
>
> Why not?
>
> If a pointer does not point to an object then there is no definition of
> "the same object".
>
> And it is common practice and sometimes very useful that
> reference-equals comparisons return true if both operands point to the
> same object /or/ both are NULL.
*> Yes, that is common practice.

In the case of shared_ptr's, it is wrong, in my situation, to take a
NULL pointer as a shared reference. I am interested only in the
relationship reflected by the use_count() .

A NULL pointer has an address, say, of 0, so this cannot be used to
determine whether two shared_ptr's are managing the same object. If one
of the two shared_ptr's does reset( new T ), then the two shared_ptr's
will both be managing a bona fide same object. So, even if the managed
object is NULL, the relationship between the two shared_ptr's is
maintained. The use_count() is (at least) two for the two shared_ptr's,
even if they are sharing only NULL.

On 04/12/2015 06:29 AM, Öö Tiib wrote:
>> Also, conceptually I do not get why such a feature would be useful. A
>> smartpointer becomes NULL only if I assign NULL to it. Why should it then
>> remember to which object it pointed earlier? If I wanted to remember that,
>> I would not have assigned NULL to it in the first place.
>

As pointed out, above, shared_ptr's do remember the relationship, even
if they are assigned NULL. The point I am making is that I would like
to be able to query that relationship, even if the pointer value is NULL.

> Maybe what he wants is something achievable with
> 'std::shared_ptr::owner_before' or 'std::shared_ptr::owner_less'. He did
> not describe it too well.
>

I'm sorry, I don't understand these suggestions. The reason that I want
the id() feature, is so that I can save shared_ptr's to disk, and when
they get restored to RAM, they maintain the same relationship.
Currently, when the shared_ptr's are NULL, I cannot do this. During the
running of the program, one of the shared_ptr's might do a reset( new T
), and all the (intended) shared_ptr's must see the change.

Öö Tiib

unread,
Apr 12, 2015, 3:19:00 PM4/12/15
to
On Sunday, 12 April 2015 20:03:44 UTC+3, Norman J. Goldstein wrote:
> Thanks for all the responses. I will address all the comments and
> clarify, further.
>
> On Sunday, 12 April 2015 11:20:06 UTC+3, Marcel Mueller wrote:
> > On 12.04.15 09.57, Norman J. Goldstein wrote:
> >> I would find it helpful for a shared_ptr to have an id() method, so that
> >> two shared_ptr's manage the same object only if and only if they have
> >> the same id's. If the managed object is not NULL, then the address of
> >> the object can work as an id. Obviously, this does not work if the
> >> object is NULL.
> >
> > Why not?
> >
> > If a pointer does not point to an object then there is no definition of
> > "the same object".
> >
> > And it is common practice and sometimes very useful that
> > reference-equals comparisons return true if both operands point to the
> > same object /or/ both are NULL.
> *> Yes, that is common practice.
>
> In the case of shared_ptr's, it is wrong, in my situation, to take a
> NULL pointer as a shared reference. I am interested only in the
> relationship reflected by the use_count().

The 'use_count()' is required to return zero when 'shared_ptr' is empty.
So if you are not interested in the situation (for example since there
is nothing further to serialize) then why you care if they compare equal
or no?

> A NULL pointer has an address, say, of 0, so this cannot be used to
> determine whether two shared_ptr's are managing the same object. If one
> of the two shared_ptr's does reset( new T ), then the two shared_ptr's
> will both be managing a bona fide same object. So, even if the managed
> object is NULL, the relationship between the two shared_ptr's is
> maintained. The use_count() is (at least) two for the two shared_ptr's,
> even if they are sharing only NULL.

Every 'shared_ptr<X>' is separate and if one starts to point at
something else then others don't.

> On 04/12/2015 06:29 AM, Öö Tiib wrote:

Following was written by Paavo Helde:

> >> Also, conceptually I do not get why such a feature would be useful. A
> >> smartpointer becomes NULL only if I assign NULL to it. Why should it then
> >> remember to which object it pointed earlier? If I wanted to remember that,
> >> I would not have assigned NULL to it in the first place.
> >
>
> As pointed out, above, shared_ptr's do remember the relationship, even
> if they are assigned NULL. The point I am making is that I would like
> to be able to query that relationship, even if the pointer value is NULL.

They aren't required to remember any relationships; empty 'shared_ptr'
is empty regardless if the object at what it pointed still exists
or not. I am not sure what relationship.

That was written by me:
> > Maybe what he wants is something achievable with
> > 'std::shared_ptr::owner_before' or 'std::shared_ptr::owner_less'. He did
> > not describe it too well.
>
> I'm sorry, I don't understand these suggestions. The reason that I want
> the id() feature, is so that I can save shared_ptr's to disk, and when
> they get restored to RAM, they maintain the same relationship.

http://isocpp.org/wiki/faq/serialization

The 'shared_ptr' is like ordinary pointer that can point at object at
what other pointers can point too. It does not provide indexing
services. So you have to maintain some map (for example like
'std::map<std::weak_ptr<X>,unsigned>' or 'std::map<X const*,unsigned>')
to map the shared object you serialize to some numeric id.

> Currently, when the shared_ptr's are NULL, I cannot do this. During the
> running of the program, one of the shared_ptr's might do a reset( new T
> ), and all the (intended) shared_ptr's must see the change.

I do not understand. Lets imagine there are two 'shared_ptr's p1 and p2
and two objects o1 and o2. All the 9 combinations of states of
pointers is on following diagram:

p1 | p2
--------------
1) null | null
2) null | o1
3) null | o2
4) o1 | null
5) o1 | o1
6) o1 | o2
7) o2 | null
8) o2 | o1
9) o2 | o2

What is the difference for p2 if the state transits from 1) to
4) or if the state transits from 5) to 8)? It can't see anything
anyway ... it still is empty or points at o1 and it does not know
where p1 points. Please clarify where is difference and why they
should not compare equal in state 1).

Norman J. Goldstein

unread,
Apr 12, 2015, 4:09:24 PM4/12/15
to
NULL and empty are not the same thing for shared_ptr.
///////////////////////////////
#include <iostream>
#include <memory>
using namespace std;

int main( int argc, char* argv[] )
{
shared_ptr< int > s1;
shared_ptr< int > s2( s1 );

cout << "s1 links= " << s1.use_count() << endl;
cout << "s2 links= " << s2.use_count() << endl;

s1.reset( (int*)nullptr );
s2 = s1;

cout << "s1 links= " << s1.use_count() << endl;
cout << "s2 links= " << s2.use_count() << endl;

return 0;
}// main
////////////////////////////////
Here is the output of the program:

s1 links= 0
s2 links= 0
s1 links= 2
s2 links= 2

Norman J. Goldstein

unread,
Apr 12, 2015, 4:29:29 PM4/12/15
to
I think I understand, now, what you are saying.
If the shared_ptr's are managing a NULL, there is no way to get the same
set to manage an actual object.

Each shared_ptr contains a pointer to the object. I had imagined that
the pointer to the object was actually in the control block.

Thank you.



Öö Tiib

unread,
Apr 12, 2015, 5:09:22 PM4/12/15
to
It is bit trickier than that. The shared_ptr has 13 constructors 9 of
what are templates so it can be made to do huge pile of tricks.
There are two object pointers. What shared pointer "owns" (IOW to what
will be called deleter when the use count drops to zero) is pointed
by control block. What shared_ptr "points at" is in shared_ptr itself.

0 new messages