From: DeMarcus on
Hi,
I have some trouble understanding the true meaning of const.
Please consider this example.

class Store
{
public:
void add( int* item ) { /* ... */ }
};

class Item
{
public:
Item( int item ) : item_(item) {}
void giveToStore( Store& store ) const { store.add( &item_ ); }

private:
int item_;
};

Now, this gives me "invalid conversion from 'const int*' to 'int*'" when
exposing item_ in store.add( &item_ ). What's the way of thinking here?
I have several options.

1. Remove const from giveToStore. This seems wrong since giveToStore()
does not alter any internals, hence it should be const. Pretty much like
boost::shared_ptr::get().

2. Do a const_cast, i.e. store.add( const_cast<int*>(&i_) );
I don't like const_cast, it immediately seems like wrong design.

3. Make i_ mutable, i.e. mutable int i_;
Seems like what I'm looking for, however, great care has to be taken so
we later don't add another const function that accidentally alters i_.

4. Redesign according to C++ Coding Standards by Sutter & Alexandrescu,
Item 11 - Hide information. Basically it says; "Don't expose internal
information from an entity that provides an abstraction.". However, my
real problem (illustrated with Item) is a kind of wrapper similar to
boost::shared_ptr and I need something like boost::shared_ptr::get().
Therefore I'm clueless about finding an alternative design.


How would you approach such const situation?

Thanks,
Daniel


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Bart van Ingen Schenau on
On Feb 19, 2:26 am, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote:
> Hi,
> I have some trouble understanding the true meaning of const.
> Please consider this example.
>
> class Store
> {
> public:
> void add( int* item ) { /* ... */ }
>
> };
>
> class Item
> {
> public:
> Item( int item ) : item_(item) {}
> void giveToStore( Store& store ) const { store.add( &item_ ); }
>
> private:
> int item_;
>
> };
>
> Now, this gives me "invalid conversion from 'const int*' to 'int*'" when
> exposing item_ in store.add( &item_ ). What's the way of thinking here?
> I have several options.
>
> 1. Remove const from giveToStore. This seems wrong since giveToStore()
> does not alter any internals, hence it should be const. Pretty much like
> boost::shared_ptr::get().

How do you know that giveToStore() does not cause item_ to be changed?
The function passes it as a writable pointer on to Store::add(), which
might try to update the object passed to it (if not now, then possibly
in a future revision).

In your options, you were missing number one:
1a. Change the function Store::add() to accept a 'const int *', or
provide an overload that accepts such a parameter.

<snip>
> How would you approach such const situation?

I would either change Store::add, or I would make giveToStore non-
const, or I would do a complete re-design as last resort. All the rest
of your options were just hacks to appease the compiler.

>
> Thanks,
> Daniel
>
Bart v Ingen Schenau


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Marco Nef on
"DeMarcus" <use_my_alias_here(a)hotmail.com> schrieb im Newsbeitrag
news:4b7d4a63$0$282$14726298(a)news.sunsite.dk...
> Hi,
> I have some trouble understanding the true meaning of const.
> Please consider this example.
>
.....
> Now, this gives me "invalid conversion from 'const int*' to 'int*'" when
> exposing item_ in store.add( &item_ ). What's the way of thinking here?
> I have several options.
>
> 1. Remove const from giveToStore. This seems wrong since giveToStore()
> does not alter any internals, hence it should be const. Pretty much like
> boost::shared_ptr::get().
>
> 2. Do a const_cast, i.e. store.add( const_cast<int*>(&i_) );
> I don't like const_cast, it immediately seems like wrong design.
>
> 3. Make i_ mutable, i.e. mutable int i_;
> Seems like what I'm looking for, however, great care has to be taken so
> we later don't add another const function that accidentally alters i_.
>
> 4. Redesign according to C++ Coding Standards by Sutter & Alexandrescu,
> Item 11 - Hide information. Basically it says; "Don't expose internal
> information from an entity that provides an abstraction.". However, my
> real problem (illustrated with Item) is a kind of wrapper similar to
> boost::shared_ptr and I need something like boost::shared_ptr::get().
> Therefore I'm clueless about finding an alternative design.
>
>
> How would you approach such const situation?

It is correct, that the method "giveToStore" does not change its member, but
it gives away the guarantee that the member won't be changed anywhere else.
So it's definitely not const.

I can see two possibilities:
- Implement a store that does not change the items so they can be const
within the store.
- Take away the const of "giveToStore".
- mutable and const_cast almost always identify design errors.

Marco


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: peter koch larsen on
On 19 Feb., 02:26, DeMarcus <use_my_alias_h...(a)hotmail.com> wrote:
> Hi,
> I have some trouble understanding the true meaning of const.
> Please consider this example.
>
> class Store
> {
> public:
> void add( int* item ) { /* ... */ }
>
> };
>
> class Item
> {
> public:
> Item( int item ) : item_(item) {}
> void giveToStore( Store& store ) const { store.add( &item_ ); }
>
> private:
> int item_;
>
> };
>
> Now, this gives me "invalid conversion from 'const int*' to 'int*'" when
> exposing item_ in store.add( &item_ ). What's the way of thinking here?
> I have several options.
>
> 1. Remove const from giveToStore. This seems wrong since giveToStore()
> does not alter any internals, hence it should be const. Pretty much like
> boost::shared_ptr::get().
>
No. Looking at the declaration of Store::add, Item::GiveToStore can't
be const (Store::add changes what is passed to it), so you should
remove const from GiveToStore.

> 2. Do a const_cast, i.e. store.add( const_cast<int*>(&i_) );
> I don't like const_cast, it immediately seems like wrong design.

I agree.

>
> 3. Make i_ mutable, i.e. mutable int i_;
> Seems like what I'm looking for, however, great care has to be taken so
> we later don't add another const function that accidentally alters i_.

Mutable should be used only for parts that "really don't belong to the
object". Mutable objects are used to cache calculations.
>
> 4. Redesign according to C++ Coding Standards by Sutter & Alexandrescu,
> Item 11 - Hide information. Basically it says; "Don't expose internal
> information from an entity that provides an abstraction.". However, my
> real problem (illustrated with Item) is a kind of wrapper similar to
> boost::shared_ptr and I need something like boost::shared_ptr::get().
> Therefore I'm clueless about finding an alternative design.

I don't really understand that part.
>
> How would you approach such const situation?

As said, I would remove the const from AddToStore. It might just be
possible, however, that the problem is with Store::add. Does it really
need to modify its argument? If not, you should add a const and make
Store::add take an int const*.

/Peter


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Paul Bibbings on
DeMarcus <use_my_alias_here(a)hotmail.com> writes:

> Hi,
> I have some trouble understanding the true meaning of const.
> Please consider this example.
>
> class Store
> {
> public:
> void add( int* item ) { /* ... */ }
> };
>
> class Item
> {
> public:
> Item( int item ) : item_(item) {}
> void giveToStore( Store& store ) const { store.add( &item_ ); }
>
> private:
> int item_;
> };
>
> Now, this gives me "invalid conversion from 'const int*' to 'int*'" when
> exposing item_ in store.add( &item_ ). What's the way of thinking here?
> I have several options.

<snip />

Whilst not wanting to reject out of hand the options you outine <snipped> I
I have the sense that, in cases where such workarounds seem required by a
given design, this is usually indicative of there being serious
flaws in the design itself, which should probably be reconsidered as a
whole.

In the case of your design here I have a sense of ill ease arising from
the issue of lifetimes. You're wanting your Store instances to maintain
pointers to a data member of Items instances when those instances
themselves are not managed by the Store. What happens to the viability
of your store if/when its `Items' go out of scope?

Though I am sure that your example here is reduced greatly from the
problem you are actually working on, could it fit into your wider model
to have your Store maintain the Item instances themselves? Then, if it
still appears correct to not expose the data member Item::item widely,
you could simply make Store a friend of Item, or some such thing. In
any event, I would want to suggest that under such a model the whole
const/non-const issue you are encountering would become much less
troublesome, if it didn't vanish altogether.

But, of course, I do not know your wider design, so some or all of this
could be inappropriate/inapplicable.

Regards

Paul Bibbings

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]