shared_ptr and const

Discussion in 'C++' started by Tim H, May 28, 2007.

  1. Tim H

    Tim H Guest

    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, May 28, 2007
    #1
    1. Advertising

  2. Tim H

    Pete Becker Guest

    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)
    Pete Becker, May 28, 2007
    #2
    1. Advertising

  3. Tim H

    Dizzy Guest

    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<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?


    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
    Dizzy, May 29, 2007
    #3
  4. Tim H

    Tim H Guest

    On May 29, 6:11 am, Dizzy <> wrote:
    > 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<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?

    >
    > As someone already replied you confuse "const int*" which is actually
    > equivalent to "int const*" andshared_ptr<const int> with "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<T> const". 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<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
    Tim H, Jun 1, 2007
    #4
  5. Tim H

    James Kanze Guest

    On Jun 1, 3:50 am, Tim H <> wrote:
    > On May 29, 6:11 am, Dizzy <> 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:
    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
    James Kanze, Jun 1, 2007
    #5
  6. Tim H

    Tim H Guest

    On Jun 1, 6:32 am, James Kanze <> 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?
    Tim H, Jun 1, 2007
    #6
  7. Tim H

    James Kanze Guest

    On Jun 1, 5:27 pm, Tim H <> wrote:
    > On Jun 1, 6:32 am, James Kanze <> 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:
    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
    James Kanze, Jun 1, 2007
    #7
  8. Tim H

    BobR Guest

    James Kanze <> 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, Jun 2, 2007
    #8
  9. BobR schrieb:
    > James Kanze <> 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, Jun 2, 2007
    #9
  10. Tim H

    BobR Guest

    Thomas J. Gritzan <> wrote in message...
    > BobR schrieb:
    > > James Kanze <> 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* 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
    BobR, Jun 2, 2007
    #10
  11. Tim H

    James Kanze Guest

    On Jun 1, 3:32 pm, James Kanze <> 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:
    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
    James Kanze, Jun 3, 2007
    #11
  12. Tim H

    James Kanze Guest

    On Jun 2, 2:01 am, "BobR" <> wrote:
    > James Kanze <> 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).


    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:
    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
    James Kanze, Jun 3, 2007
    #12
  13. 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
    Thomas J. Gritzan, Jun 3, 2007
    #13
  14. Tim H

    BobR Guest

    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
    BobR, Jun 3, 2007
    #14
  15. Tim H

    BobR Guest

    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
    BobR, Jun 3, 2007
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Colin Caughie
    Replies:
    1
    Views:
    710
    Shooting
    Aug 29, 2006
  2. Replies:
    11
    Views:
    1,098
  3. Javier
    Replies:
    2
    Views:
    557
    James Kanze
    Sep 4, 2007
  4. 0m
    Replies:
    26
    Views:
    1,109
    Tim Rentsch
    Nov 10, 2008
  5. fungus
    Replies:
    13
    Views:
    882
    fungus
    Oct 31, 2008
Loading...

Share This Page