By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,905 Members | 1,271 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,905 IT Pros & Developers. It's quick & easy.

shared_ptr and const

P: n/a
I understand the semantics of why this works the way it does. But I
wonder if there's a reason for the behaviore at the line marked
"QUESTION". I figured if there is an answer, someone here knows it.

Specifically, part 1 is obvious to most anyone. Part 2 is isomorphic
to part 1, yet behaves differently. If a shared_ptr is const, should
it really allow non-const dereferences?

Thanks,

Tim

#include <boost/shared_ptr.hpp>

int main(void)
{
// part 1
int *pi = new int(1);
const int *cpi = new int(2);

*pi = 11; // ok
*cpi = 22; // compile error

// part 2
boost::shared_ptr<intspi(new int(3));
const boost::shared_ptr<intcspi(new int(4));

*spi = 33; // ok
*cspi = 44; // QUESTION: should this be a compile
error?

// part 3
boost::shared_ptr<const intspci(new int(5));
const boost::shared_ptr<const intcspci(new int(6));

*spci = 44; // compile error
*cspci = 55; // compile error

return 0;
}

May 28 '07 #1
Share this Question
Share on Google+
14 Replies


P: n/a
Tim H wrote:
>
// part 2
boost::shared_ptr<intspi(new int(3));
const boost::shared_ptr<intcspi(new int(4));

*spi = 33; // ok
*cspi = 44; // QUESTION: should this be a compile
error?
ANSWER: no. cspi is a const pointer to int, not a pointer to const int.
The analogous pointer would be:

int * const cip;

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
May 28 '07 #2

P: n/a
Tim H wrote:
I understand the semantics of why this works the way it does. But I
wonder if there's a reason for the behaviore at the line marked
"QUESTION". I figured if there is an answer, someone here knows it.

Specifically, part 1 is obvious to most anyone. Part 2 is isomorphic
to part 1, yet behaves differently. If a shared_ptr is const, should
it really allow non-const dereferences?

Thanks,

Tim

#include <boost/shared_ptr.hpp>

int main(void)
{
// part 1
int *pi = new int(1);
const int *cpi = new int(2);

*pi = 11; // ok
*cpi = 22; // compile error

// part 2
boost::shared_ptr<intspi(new int(3));
const boost::shared_ptr<intcspi(new int(4));

*spi = 33; // ok
*cspi = 44; // QUESTION: should this be a compile
error?
As someone already replied you confuse "const int*" which is actually
equivalent to "int const*" and shared_ptr<const intwith "int* const"
which is equivalent to "const shared_ptr<int>" (or "shared_ptr<int>
const").

In the first case it's the memory pointed to that is constant. In the second
case it's the pointer itself (or shared_ptr) that is constant.

Generally prefer the form of "T const*" over to "const T*" because:
1. it doesn't create such confusions
2. it will not give you strange errors when dealing with template code and
typedefs, example of such code(quote from C++ Templates Complete Guide):

typedef char* CHARS;
typedef CHARS const CPTR; // constant pointer to chars

The meaning of the second declaration is preserved when we textually replace
CHARS with what it stands for:
typedef char* const CPTR; // constant pointer to chars

However, if we write const before the type it qualifies, this principle
doesn't apply. Indeed, consider the alternative to our first two type
definitions presented earlier:
typedef char* CHARS;
typedef const CHARS CPTR; // constant pointer to chars

Textually replacing CHARS results in a type with a different meaning:
typedef const char* CPTR; // pointer to constant chars

typedefs are textually replaced thus can get into errors when using const
before the const type.
// part 3
boost::shared_ptr<const intspci(new int(5));
const boost::shared_ptr<const intcspci(new int(6));

*spci = 44; // compile error
*cspci = 55; // compile error

return 0;
}
shared_ptr<tries to behave like a normal pointer/reference. And with
pointer/references you have what is called "bitwise constness" as oposed
to "logical constness", ie having a const pointer ("int* const pi = &i")
doesn't restrict the access to the memory pointed to, it just restricts the
access to the pointer itself ("pi = &another;" will error but "*pi = 10"
will not).

In conclusion, if you don't want non-const access to the pointed to object
then make it "shared_ptr<T const>" and not "shared_ptr<Tconst". They are
very different...

--
Dizzy

May 29 '07 #3

P: n/a
On May 29, 6:11 am, Dizzy <d...@roedu.netwrote:
Tim H wrote:
I understand the semantics of why this works the way it does. But I
wonder if there's a reason for the behaviore at the line marked
"QUESTION". I figured if there is an answer, someone here knows it.
Specifically, part 1 is obvious to most anyone. Part 2 is isomorphic
to part 1, yet behaves differently. If ashared_ptris const, should
it really allow non-const dereferences?
Thanks,
Tim
#include <boost/shared_ptr.hpp>
int main(void)
{
// part 1
int *pi = new int(1);
const int *cpi = new int(2);
*pi = 11; // ok
*cpi = 22; // compile error
// part 2
boost::shared_ptr<intspi(new int(3));
const boost::shared_ptr<intcspi(new int(4));
*spi = 33; // ok
*cspi = 44; // QUESTION: should this be a compile
error?

As someone already replied you confuse "const int*" which is actually
equivalent to "int const*" andshared_ptr<const intwith "int* const"
which is equivalent to "constshared_ptr<int>" (or "shared_ptr<int>
const").
In conclusion, if you don't want non-const access to the pointed to object
then make it "shared_ptr<T const>" and not "shared_ptr<Tconst". They are
very different...

I fully apprciate the literal difference. What I am curious about is
parallelism to native pointers.

WHY is it so? Why would it be a bad idea to sub-class shared_ptr and
make "operator->() const" and "operator*() const" return const
references?

The parallel usage is what I want.

const int *cpi = new int;
const shared_ptr<intshcpi = new int;

*cpi = 2;
*thcpi = 2;

This example is trivial to change, but every piece of code I see does

typedef shared_ptr<intint_ptr;

So now we always have to have a second typedef for const_int_ptr;

Whipping up a trivial sub-class is easy. So why is it a bad idea?

Thanks,

Tim

Jun 1 '07 #4

P: n/a
On Jun 1, 3:50 am, Tim H <thoc...@gmail.comwrote:
On May 29, 6:11 am, Dizzy <d...@roedu.netwrote:
Tim H wrote:
WHY is it so? Why would it be a bad idea to sub-class shared_ptr and
make "operator->() const" and "operator*() const" return const
references?
Because this doesn't mimic the way raw pointers work; it has
counter intuitive semantics.
The parallel usage is what I want.
const int *cpi = new int;
const shared_ptr<intshcpi = new int;
But those aren't parallel. The parallels would be:
int const* cpi = new int ;
shared_ptr< int const shcpi = new int ;
or
int* const cpi = new int ;
shared_ptr< int const shcpi = new int ;

A shared_ptr mimics the semantics of the pointer. And the
const-ness of the pointer is orthogonal to the const-ness of
what is pointed to:
int* p0 ;
int const* p1 ;
int* const p2 ;
int* const* p3 ;
gives:
shared_ptr< int p0 ;
shared_ptr< int const p1 ;
shared_ptr< int const p2 ;
shared_ptr< int const const p3 ;

More generally, "shared_ptr<T>" mimics "T*".
*cpi = 2;
*thcpi = 2;
This example is trivial to change, but every piece of code I see does

typedef shared_ptr<intint_ptr;
So now we always have to have a second typedef for const_int_ptr;
And how is this any different than with a raw pointer?
Whipping up a trivial sub-class is easy. So why is it a bad idea?
Because the results aren't really a "smart pointer", and don't
behave intuitively.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 1 '07 #5

P: n/a
On Jun 1, 6:32 am, James Kanze <james.ka...@gmail.comwrote:
WHY is it so? Why would it be a bad idea to sub-class shared_ptr and
make "operator->() const" and "operator*() const" return const
references?

Because this doesn't mimic the way raw pointers work; it has
counter intuitive semantics.
I beg to differ, here.

I can not take all my code that uses "foo *" and "const foo *" and
drop in my typedef'ed foo_ptr. Instead I need to drop in a 2nd
typedef.
This example is trivial to change, but every piece of code I see does
typedef shared_ptr<intint_ptr;
So now we always have to have a second typedef for const_int_ptr;

And how is this any different than with a raw pointer?
If I have "foo *" and want to qualify it as const, I simply add
"const" before it. If I have a typedef'ed "foo_ptr", and I want to
change it to a const, I add a second typedef and change the typedef I
am using.

It's the lack of being able to globally search and replace "foo *"
with "foo_ptr" that irks me.
Whipping up a trivial sub-class is easy. So why is it a bad idea?

Because the results aren't really a "smart pointer", and don't
behave intuitively.
If I say that they behave intuitively for me, is there any caveat or
reason I should not do this for my own code?

Jun 1 '07 #6

P: n/a
On Jun 1, 5:27 pm, Tim H <thoc...@gmail.comwrote:
On Jun 1, 6:32 am, James Kanze <james.ka...@gmail.comwrote:
WHY is it so? Why would it be a bad idea to sub-class shared_ptr and
make "operator->() const" and "operator*() const" return const
references?
Because this doesn't mimic the way raw pointers work; it has
counter intuitive semantics.
I beg to differ, here.
I can not take all my code that uses "foo *" and "const foo *" and
drop in my typedef'ed foo_ptr. Instead I need to drop in a 2nd
typedef.
In place of what? If you have:
typedef foo* FooPtr ;
you can replace it trivially with:
typedef shared_ptr< foo FooPtr ;
with exactly the same behavior.

If you have "foo*" and "foo const*", obviously, you'll need two
different shared_ptr. The same as if you had "foo*" and "bar*".
It's more or less the same relationship.
This example is trivial to change, but every piece of code I see does
typedef shared_ptr<intint_ptr;
So now we always have to have a second typedef for const_int_ptr;
And how is this any different than with a raw pointer?
If I have "foo *" and want to qualify it as const, I simply add
"const" before it.
You can, but it's a lot clearer if you add the const after the
foo. Const normally modifies what precedes it.
If I have a typedef'ed "foo_ptr", and I want to
change it to a const, I add a second typedef and change the typedef I
am using.
Exactly the same as with a pointer. If you typedef a pointer,
and what to change it to point to const, you need a second
typedef.
It's the lack of being able to globally search and replace "foo *"
with "foo_ptr" that irks me.
Whipping up a trivial sub-class is easy. So why is it a bad idea?
Because the results aren't really a "smart pointer", and don't
behave intuitively.
If I say that they behave intuitively for me, is there any caveat or
reason I should not do this for my own code?
Because it confuse anyone who knows C++? Because it violates
the type system? Because it links the const-ness of two
different, unrelated objects?

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 1 '07 #7

P: n/a

James Kanze <ja*********@gmail.comwrote in message ...

/* """
A shared_ptr mimics the semantics of the pointer. And the
const-ness of the pointer is orthogonal to the const-ness of
what is pointed to:
int* p0 ;
int const* p1 ;
int* const p2 ;
int* const* p3 ;
gives:
shared_ptr< int p0 ;
shared_ptr< int const p1 ;
shared_ptr< int const p2 ;
shared_ptr< int const const p3 ;

""" */
int * const *p3 ;
The 'int' is read-write, the 'pointer-to-pointer' is read-only, '*p3' is rw:
shared_ptr< int const const p3 ;
So, this p3 does not look correct to me (i am not familiar with boost).
Seems to me like it might be (?):

shared_ptr< int * const p3 ;
or:
shared_ptr< int const *p3 ;
or:
shared_ptr< shared_ptr< int const p3 ; // are they 'nestable'
or?

Just because I don't need/use them now doesn't mean that someday I might
desperately need shared_ptr<>. Could you clarify this point?

[ Dang, now I need to re-review Alf's 'Pointer' PDF!! <G>]
--
Bob R
POVrookie
Jun 2 '07 #8

P: n/a
BobR schrieb:
James Kanze <ja*********@gmail.comwrote in message ...

/* """
A shared_ptr mimics the semantics of the pointer. And the
const-ness of the pointer is orthogonal to the const-ness of
what is pointed to:
int* p0 ;
int const* p1 ;
int* const p2 ;
int* const* p3 ;
gives:
shared_ptr< int p0 ;
shared_ptr< int const p1 ;
shared_ptr< int const p2 ;
shared_ptr< int const const p3 ;
Are you sure about p3?

int const* const p3;
gives:
shared_ptr< int const const p3 ;

--
Thomas
http://www.netmeister.org/news/learn2quote.html
Jun 2 '07 #9

P: n/a

Thomas J. Gritzan <Ph*************@gmx.dewrote in message...
BobR schrieb:
James Kanze <ja*********@gmail.comwrote in message ...

/* """
A shared_ptr mimics the semantics of the pointer. And the
const-ness of the pointer is orthogonal to the const-ness of
what is pointed to:
int* const* p3 ;
gives:
shared_ptr< int const const p3 ;

Are you sure about p3?

int const* const p3;
gives:
shared_ptr< int const const p3 ;
Hi Thomas,

Are you answering me or James?
( I used makeshift quotes /* """ ... """ */ for James' post.).

I was asking about James':
int * const *p3;

My 'guess' ( assuming 'shared_ptr' is nestable):
shared_ptr< shared_ptr< int const p3 ; // are they 'nestable'?

Does that seem correct?

I don't have 'boost', so, I can't 'test' it (I'll wait for TR1 or?).
Thanks.
--
Bob R
POVrookie
Jun 2 '07 #10

P: n/a
On Jun 1, 3:32 pm, James Kanze <james.ka...@gmail.comwrote:

Sorry about this: there's an obvious error in the following:
A shared_ptr mimics the semantics of the pointer. And the
const-ness of the pointer is orthogonal to the const-ness of
what is pointed to:
int* p0 ;
int const* p1 ;
int* const p2 ;
int* const* p3 ;
This last line should be:

int const* const p3 ;
gives:
shared_ptr< int p0 ;
shared_ptr< int const p1 ;
shared_ptr< int const p2 ;
shared_ptr< int const const p3 ;
More generally, "shared_ptr<T>" mimics "T*".
--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 3 '07 #11

P: n/a
On Jun 2, 2:01 am, "BobR" <removeBadB...@worldnet.att.netwrote:
James Kanze <james.ka...@gmail.comwrote in message ...

/* """
A shared_ptr mimics the semantics of the pointer. And the
const-ness of the pointer is orthogonal to the const-ness of
what is pointed to:
int* p0 ;
int const* p1 ;
int* const p2 ;
int* const* p3 ;
gives:
shared_ptr< int p0 ;
shared_ptr< int const p1 ;
shared_ptr< int const p2 ;
shared_ptr< int const const p3 ;

""" */
int * const *p3 ;
The 'int' is read-write, the 'pointer-to-pointer' is read-only, '*p3' is rw:
shared_ptr< int const const p3 ;
So, this p3 does not look correct to me (i am not familiar with boost).
The error is in the raw pointer line, where I duplicated the *,
and not the const, like I meant to. The above is the equivalent
of:

int const* const p3 ;
Seems to me like it might be (?):
shared_ptr< int * const p3 ;
or:
shared_ptr< int const *p3 ;
or:
shared_ptr< shared_ptr< int const p3 ; // are they 'nestable'
or?
The last. They're nestable. Not that I think that you ever
should nest them. (In practice, I don't use them very often
anyway.)
Just because I don't need/use them now doesn't mean that someday I might
desperately need shared_ptr<>. Could you clarify this point?
If you can't use Boost, Barton and Nackman have an example of a
very similar shared_ptr.

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 3 '07 #12

P: n/a
BobR wrote:
[...]
Hi Thomas,

Are you answering me or James?
( I used makeshift quotes /* """ ... """ */ for James' post.).
I was answering to you, since I didn't notice the quotes (BTW why is
everyone using non-standard quotes?)
But you are right, it should be a reply to James.
I was asking about James':
int * const *p3;

My 'guess' ( assuming 'shared_ptr' is nestable):
shared_ptr< shared_ptr< int const p3 ; // are they 'nestable'?
As James already explained else thread, it should be
int const* const p3;

A nested shared_ptr<rarely would make sense.

--
Thomas
http://www.netmeister.org/news/learn2quote.html
Jun 3 '07 #13

P: n/a

James Kanze wrote in message...

/* """ // <--- note the quote <G>
On Jun 2, 2:01 am, "BobR" wrote:
int * const *p3 ;
The 'int' is read-write, the 'pointer-to-pointer' is read-only, '*p3' is
rw:
shared_ptr< int const const p3 ;
So, this p3 does not look correct to me (i am not familiar with boost).
The error is in the raw pointer line, where I duplicated the *,
and not the const, like I meant to. The above is the equivalent
of:
int const* const p3 ;
Seems to me like it might be (?):
[snip]
or:
shared_ptr< shared_ptr< int const p3 ; // are they 'nestable'
or?
The last. They're nestable. Not that I think that you ever
should nest them. (In practice, I don't use them very often
anyway.)
""" */

Yeah, I use them *very* little. That's why I wanted to clarify the issue.
Thank you very much.

/* """
Just because I don't need/use them now doesn't mean that someday I might
desperately need shared_ptr<>. Could you clarify this point?
If you can't use Boost, Barton and Nackman have an example of a
very similar shared_ptr.
""" */

It's not that I can't use 'boost', it's that I don't have it yet. :-}
I prefer to write my own 'clean-up' code for now (learning thing).
I'll probably use 'shared_ptr' when it is incorporated into the standard.

Thanks again, James.

--
Bob R
POVrookie
Jun 3 '07 #14

P: n/a

Thomas J. Gritzan wrote in message...
BobR wrote:
[...]
Hi Thomas,
Are you answering me or James?
( I used makeshift quotes /* """ ... """ */ for James' post.).

I was answering to you, since I didn't notice the quotes
** (BTW why is everyone using non-standard quotes?) **
Older newsreaders. (I have recently come *up* to OE5!! <G>[1])
But you are right, it should be a reply to James.
I was asking about James':
int * const *p3;

My 'guess' ( assuming 'shared_ptr' is nestable):
shared_ptr< shared_ptr< int const p3 ; // are they 'nestable'?

As James already explained else thread, it should be
int const* const p3;

A nested shared_ptr<rarely would make sense.
I agree. I just wanted to clarify the syntax (for future).

Thanks Thomas.

[1] - Homey don't play (or pay) ms.
--
Bob R
POVrookie
Jun 3 '07 #15

This discussion thread is closed

Replies have been disabled for this discussion.