From: Nick Hounsome on
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
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
>
> 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
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
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! ]