Home     |     .Net Programming    |     cSharp Home    |     Sql Server Home    |     Javascript / Client Side Development     |     Ajax Programming

Ruby on Rails Development     |     Perl Programming     |     C Programming Language     |     C++ Programming     |     IT Jobs

Python Programming Language     |     Laptop Suggestions?    |     TCL Scripting     |     Fortran Programming     |     Scheme Programming Language


 
 
Cervo Technologies
The Right Source to Outsource

MS Dynamics CRM 3.0

C++ Programming

shared_ptr and const


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<int> spi(new int(3));
        const boost::shared_ptr<int> cspi(new int(4));

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

        // part 3
        boost::shared_ptr<const int> spci(new int(5));
        const boost::shared_ptr<const int> cspci(new int(6));

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

        return 0;

Tim H wrote:

>         // part 2
>         boost::shared_ptr<int> spi(new int(3));
>         const boost::shared_ptr<int> cspi(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)

As someone already replied you confuse "const int*" which is actually
equivalent to "int const*" and shared_ptr<const int> with "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 int> spci(new int(5));
>         const boost::shared_ptr<const int> cspci(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<T> const". They are
very different...

--
Dizzy

On May 29, 6:11 am, Dizzy <d@roedu.net> wrote:

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<int> shcpi = new int;

        *cpi = 2;
        *thcpi = 2;

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

        typedef shared_ptr<int> int_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

On Jun 1, 3:50 am, Tim H <thoc@gmail.com> wrote:

> On May 29, 6:11 am, Dizzy <d@roedu.net> wrote:
> > 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<int> shcpi = 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<int> int_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:james.ka@gmail.com
Conseils en informatique oriente objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Smard, 78210 St.-Cyr-l'cole, France, +33 (0)1 30 23 00 34

On Jun 1, 6:32 am, James Kanze <james.ka@gmail.com> 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.

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<int> int_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?
On Jun 1, 5:27 pm, Tim H <thoc@gmail.com> wrote:

> On Jun 1, 6:32 am, James Kanze <james.ka@gmail.com> 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.
> 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<int> int_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: james.ka@gmail.com
Conseils en informatique oriente objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Smard, 78210 St.-Cyr-l'cole, France, +33 (0)1 30 23 00 34

James Kanze <james.ka@gmail.com> wrote 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

BobR schrieb:

> James Kanze <james.ka@gmail.com> wrote 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

Thomas J. Gritzan <Phygon_ANTIS@gmx.de> wrote in message...

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

On Jun 1, 3:32 pm, James Kanze <james.ka@gmail.com> wrote:

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: james.ka@gmail.com
Conseils en informatique oriente objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Smard, 78210 St.-Cyr-l'cole, France, +33 (0)1 30 23 00 34
On Jun 2, 2:01 am, "BobR" <removeBadB@worldnet.att.net> wrote:

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: james.ka@gmail.com
Conseils en informatique oriente objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Smard, 78210 St.-Cyr-l'cole, France, +33 (0)1 30 23 00 34

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

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

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

Add to del.icio.us | Digg this | Stumble it | Powered by Megasolutions Inc