|
|
 |
 |
 |
 |
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)
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
On May 29, 6:11 am, Dizzy <d@roedu.net> 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
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...
> 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* 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
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:
> 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).
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
|
 |
 |
 |
 |
|