Prev: return value optimization vs. returning a boost::shared_ptr of container
Next: Can const& functors be passed to functions efficiently (i.e. inlined, etc)?
From: Nick Hounsome on 15 Jun 2010 05:02 On 15 June, 15:12, Edward Rosten <edward.ros...(a)gmail.com> wrote: > On Jun 15, 10:03 am, Nick Hounsome <nick.houns...(a)gmail.com> wrote: > > > On 13 June, 11:09, "naikr...(a)gmail.com" <naikr...(a)gmail.com> wrote: > > This has been debated here before. Perhaps I have a more coherent > argument this time. > > > > Is there a safe way to treat Foo<T>* as a Foo<const T>* ? > > > Are you absolutely sure that you dont want const Foo<T>*? > > Yes... > > > IMHO It is rarely useful to have Foo<const T> because Foo can always > > protect instance of T whether they are const or not - All you acheive > > is making the implementation harder. (Foo<const T*> MIGHT make sense). > > Unfortunately, you are mistaken. Consider: > > template<class C> class Foo > { > private: > C* ptr; > public: > Foo(C* p) > :ptr(p); > > C* get(){ return ptr; } > const C* get() const { return ptr; } > > }; > > Now consider you have a function like this: > > void func(const Foo<int>& f) > { > Foo<int> not_const_anymore(f); > > *not_const_anymore.get() = 0; > > } > > Because you can copy construct a non-const object from a const one, > you can with some effort circumvent the access controls. This is only because your Foo is seriuosly flawed. It can be prevented with: Foo(const Foo<T>&) = delete; // or private unimplemented Foo& operator=(const Foo<T>&) = delete; // or provate unimplemented As a good general rule any class containing pointers should declare copy ctor and assignment operator. > > Compare your class Foo with std::vector - nobody uses vector<const > > int> but vector protects its content with overloads like > > reference operator[] ( size_type n ); > > const_reference operator[] ( size_type n ) const; > > I agree 100%. When a class has value semantics (e.g. vector<int>) a > const class behaves as if the values it points to are const. That is > nice since a const vector works as a const array. However, if you have > an object with reference semantics, it is impossible so make a const > object behave as if it points to const data properly. > > The problem is that const behaves very subtly differently for pointers > than for classes. This is well illustrated by the fact that it is > impossible to get pointer like semantics with classes. Many people > (myself included) understand the precise reasons behind how this > difference manifests, but nevertheless disagree. > > The reason is that const A* is just a const version of A*, so the > conversion can happen freely. In this case, the object IS NOT > constant. > > However, const A is a version of A, but the object IS constant. It is straightforward to provide a conversion from Foo<T> to Foo<const T> if that is what you need. As a bonus it does away with the need for all the pointers and/or references. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Chris Uzdavinis on 15 Jun 2010 09:46 On Jun 15, 9:12 am, Edward Rosten <edward.ros...(a)gmail.com> wrote: [snip] > The reason is that const A* is just a const version of A*, so the > conversion can happen freely. In this case, the object IS NOT > constant. [snip] Just to be clear, "const A *" is a pointer to a const object. The object *is* const. (The pointer itself is not.) The code that matches your words would be: A * const (which is a const pointer to a non-const object.) -- Chris -- Chris -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: naikrosh on 15 Jun 2010 23:03 > > This is an idea and depends on what you are trying to accomplish. > Thanks all for your insights. Here is more background on what I am interested in achieving. Perhaps it might help the discussion. I need a custom smart pointer with special "binding" semantics as described below : my_ptr<int> p1 = new int(2); my_ptr<int> p2 = p1; //Copy construction: now p1 & p2 are permanently "bound" together. *p2 = new int(3); // now p1 also points to 3 (as p1 and p2 are bound). 2 is freed. my_ptr<int> p3; p3 = p2; // Copy assignment: p3 takes a copy of *p2. This will not bind p3 and p2 Binding can happen only through copy construction (not copy asignment). Since multiple my_ptr can refer to the same object via binding, reference counting is used to manage the lifetime of the objects. The basic skeleton of the internal representation is as follows: template<class T> struct my_ptr { ref_counted_ptr<T>* ptr; }; template<class T> struct ref_counted_ptr { int ref_count; T* obj; //points to actual obj }; Essentially, my_ptr points to ref_counted_ptr which points to actual obj and also stores the ref count.When two or more my_ptr are bound, they point to the same ref_counted_ptr obj. Having a my_ptr point to a diff object is acheived by updating the pointer inside ref_counted_ptr which allows all bound my_ptr objects to now point to the new object. My original questions comes from my inability to find a way to allow a my_ptr<const T> to bind to my_ptr<T>. Since T* can be used where a const T* is desired (same with shared_ptr<T> & shared_ptr<const T> ). It is natural to expect similar semantics out of my_ptr. -Roshan -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Edward Rosten on 16 Jun 2010 02:44 On Jun 16, 1:46 am, Chris Uzdavinis <cuz...(a)gmail.com> wrote: > On Jun 15, 9:12 am, Edward Rosten <edward.ros...(a)gmail.com> wrote: > [snip]> The reason is that const A* is just a const version of A*, so the > > conversion can happen freely. In this case, the object IS NOT > > constant. > > [snip] > > Just to be clear, "const A *" is a pointer to a const object. > The object *is* const. (The pointer itself is not.) Depends on what you mean by "the object". The object is a pointer to a bunch of data. The object (the pointer) is not const. The bunch of data is const. > The code that matches your words would be: > > A * const No, that matches your interpretation of my words :) > (which is a const pointer to a non-const object.) -Ed -- (You can't go wrong with psycho-rats.)(http://mi.eng.cam.ac.uk/~er258) /d{def}def/f{/Times s selectfont}d/s{11}d/r{roll}d f 2/m{moveto}d -1 r 230 350 m 0 1 179{ 1 index show 88 rotate 4 mul 0 rmoveto}for/s 12 d f pop 235 420 translate 0 0 moveto 1 2 scale show showpage -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Edward Rosten on 16 Jun 2010 02:46
On Jun 15, 9:02 pm, Nick Hounsome <nick.houns...(a)gmail.com> wrote: > > Because you can copy construct a non-const object from a const one, > > you can with some effort circumvent the access controls. > > This is only because your Foo is seriuosly flawed. You are mistaken. > It can be prevented with: > > Foo(const Foo<T>&) = delete; // or private unimplemented > Foo& operator=(const Foo<T>&) = delete; // or provate unimplemented ...and that prevents one returning a Foo from a free function. Bear in mind that I'm talking about all of this in context of array slicing. It is useful to be able to generate and return slices. > As a good general rule any class containing pointers should declare > copy ctor and assignment operator. Yes, but that does not help in this case. > It is straightforward to provide a conversion from Foo<T> to Foo<const > T> > if that is what you need. No, it is not! You can define a conversion, but it will not get used automatically. Try compiling the code I posted: it has the conversion defined. It does not compile, because C++ won't do arbitrary searches through instantiating templates to find something that will match. You have to add extra syntactic overhead. > As a bonus it does away with the need for all the pointers and/or > references. I don't follow. My basic point is this: the automatic addition of const to raw pointers is perfect for implementing reference semantics. There is no way of replicating this with classes, without introducing a lot of needless syntactic overhead. This is IMO a flaw, because it means that built-in types (and worse, raw pointers) behave better than user- defined ones. But we're debating using my class Foo, which is rather feature-poor and is designed to illustrate a point. Naturally, analogies get stretched rather thin after a while. I can provide you with a link to a complete, working example of what I mean. -Ed -- (You can't go wrong with psycho-rats.)(http://mi.eng.cam.ac.uk/~er258) /d{def}def/f{/Times s selectfont}d/s{11}d/r{roll}d f 2/m{moveto}d -1 r 230 350 m 0 1 179{ 1 index show 88 rotate 4 mul 0 rmoveto}for/s 12 d f pop 235 420 translate 0 0 moveto 1 2 scale show showpage -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |