Topic: Const correctness and lazy read...
Author: meang@post.com (Meang Akira Tanaka)
Date: Thu, 7 Apr 2005 00:26:42 GMT Raw View
===================================== MODERATOR'S COMMENT:
This is getting away from the topics of comp.std.c++.
===================================== END OF MODERATOR'S COMMENT
On Tue, 5 Apr 2005 13:32:27 CST, "Nicola Musatti"
<nicola.musatti@gmail.com> wrote:
[*snip*]
>
>I do not agree. Separating the logic model from the persistence
>infrastructure improves the OO design because you separate the
>representation of a portion of the real world from low level details.
>Do you really think that a BankAccount class should have a
>readFromOracle() and a writeToOracle() member functions?
>
true when you don't have to think about performance issues such as
only getting data when necessary.
but in cases where you have a large data structure, it may be
beneficial to only read those parts that are needed when a method is
invoked and I guess there are several ways to do that:
1. Let the caller ensure that data is read.
2. Let the object itself ensure that the data is read.
>This is particularly important when you deal with complex entities,
>which otherwise would result in unmanageable classes.
>
oki so if you have lets say a bankaccount with may contain all the
transactions.
e.g.
class bankaccount
{
std::string mBankAccountNumber;
std::list<banktransaction> mTransactions;
std::string getBankAccountNumber() { ... }
}
and for one instance of the an bank account you would have 700
transaction.
If you only want to get the bank account number.
how should this be done then?
The caller could of course invoke a read method in order to get the
bankaccount. but since it doesn't really know which data to be read,
it will have to read the whole lot.
The other option is to let the class it self read the data it "thinks"
will be needed. that is if you invoke getBankAccount it may read all
the data except for the transactions.
But am not sure there are other ways or have I overlooked something
Hopes it clearifies it
br
Meanb
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: meang@post.com (Meang Akira Tanaka)
Date: Thu, 7 Apr 2005 04:22:36 GMT Raw View
On 4 Apr 2005 12:55:01 GMT, alfps@start.no (Alf P. Steinbach) wrote:
[*snip*]
>> But that is basically the two class solution
>
>?
As I understood the MutableMemberRef_ solution:
a "pointer type" is introduced in order which should handle the lazy
read. which seems like a good idea.
but as I see it it resembles the two class solution as I suggested
previously in the thread...
that is having a separate class which contains the data, and another
class having the logic.
Is that what is the intend of the MutableMemberRef_?
If that is the case as I said this would separate the logic from the
data
e.g
/**
*/
class Person
{
PersonData *ptr;
public:
Person() { ptr = new PersonData(); }
int getAge() const { return ptr->getAge(); }
void celebrateBirthdate { ptr->setAge(ptr->getAge() + 1); }
}
class PersonData
{
int mAge;
public:
int getAge() const { lazyRead(); return mAge; }
void lazyRead() { ... get data ... }
}
The question is what have we achieved by doing this?
Well For one we have separated the data from the logic.
For example celebrateBirthdate is placed in Person class rather than
in PersonData. But one could argue that one could just move
celebrateBirthdate PersonData. True. but now we have to create all the
methods that should be accessible in PersonData accessible from
Person. Well that means more work.
The other thing is that all methods in Person can basically be
declared as const as they change the state of the PersonData object
and not the Person object.
that is for example:
void celebrateBirthdate const { ptr->setAge(ptr->getAge() +
1); }
is also possible because one changes the state of the instance of
PersonData and not the state of the Person.
So we have somehow made the const keyword non effective.
>Ignoring the issue of accessing a non-mutable member this way (addressed
>in my own follow-up), in what way doesn't this fix your problem?
Well It does indeed fix my problem. but I guess not as elegant.
because the logic is separated from the logic.
>
>Exactly what _is_ the original problem then?
The original problem is how to solve that const member functions and
lazy read pattern does not mix very well.
hope this clarify it more
br
Meang
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: andre@ba-z.co.jp (Andre Caldas)
Date: Fri, 8 Apr 2005 18:50:26 GMT Raw View
> Basically for having a single or few method which are doing "dirty"
> work rather than spreading it all over the code.
Why not "const_cast"?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: brangdon@cix.co.uk (Dave Harris)
Date: Fri, 8 Apr 2005 21:56:20 GMT Raw View
wade@stoner.com () wrote (abridged):
> const_cast<T*>(this)->m_foo = bar;
>
> The only time the compiler "knows" I don't have that line is
> 1) The compiler can see the source code of my method or
> 2) The compiler can see (or infer) the definition of my object (not
> just the definition of a pointer or reference to my object) and
> 2a) the definition says my object is const and not on the heap and
> 2b) the compiler knows my method is not being called directly or
> indirectly from a constructor/destructor of my object (or of a larger
> object that contains my object as a sub-object).
Are you sure that heap-allocated const objects are the exception you note
in 2a) ?
I would have said this:
const int *p = new const int(42);
*const_cast<int *>(p) = 54; // ??
had undefined behaviour.
-- Dave Harris, Nottingham, UK.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: meang@post.com (Meang Akira Tanaka)
Date: Sun, 10 Apr 2005 19:21:53 GMT Raw View
On Fri, 8 Apr 2005 18:50:26 GMT, andre@ba-z.co.jp (Andre Caldas)
wrote:
[*snip*]
>
>Why not "const_cast"?
basically because you have to const cast all the places where there
are getters. by having one single method which does the dirty work.
There will be no need to const cast all the places.
e.g.
with const_cast
class A
{
int mAttribute1;
int mAttribute2;
int getAttribute1() const
{
A* ptr = const_cast<A*>(this);
ptr->lazyRead();
return mAttribute1;
}
int getAttribute2() const
{
A* ptr = const_cast<A*>(this);
ptr->lazyRead();
return mAttribute2;
}
void lazyRead() { ... }
}
without const_cast
class A
{
int mAttribute1;
int mAttribute2;
int getAttribute1() const
{
lazyRead();
return mAttribute1;
}
int getAttribute2() const
{
lazyRead();
return mAttribute2;
}
void lazyRead() mutable { ... }
}
br
Meang
>
>---
>[ comp.std.c++ is moderated. To submit articles, try just posting with ]
>[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
>[ --- Please see the FAQ before posting. --- ]
>[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: andre@ba-z.co.jp (Andre Caldas)
Date: Mon, 11 Apr 2005 03:53:36 GMT Raw View
Meang Akira Tanaka wrote:
>>Why not "const_cast"?
>
>
> basically because you have to const cast all the places where there
> are getters. by having one single method which does the dirty work.
Sorry, Tanaka-san!
The question was "why mutable members?"
The answer was "for having a single method doing the 'dirty' work..."
I am really new to "mutable members", but I don't think this is their
purpose.
I guess you were talking about "a single 'dirty' function that calls
'const_cast' *inside* it to do the 'dirty' work". Were you? If you were,
then it has nothing to do with "mutable members".
Sorry if I am wrong here. But in this case, please explain me what
"mutable members" are.
Andre Caldas.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Mon, 11 Apr 2005 17:56:09 GMT Raw View
* Meang Akira Tanaka:
> [snip]
> So we have somehow made the const keyword non effective.
No, not at all; see below.
> > Exactly what _is_ the original problem then?
>
> The original problem is how to solve that const member functions and
> lazy read pattern does not mix very well.
>
> hope this clarify it more
OK, I see no need for your language extension. The following program displays
42, 42 and 43. It doesn't allow willy-nilly access to the mutable members,
and it's got the logic in the same class as the data, at least conceptually.
On the other hand, as mentioned previously, I think it would be nice with
a language extension that allows class Person_Age below to be Person::Age.
Unless there's some way of doing that that I'm not familiar with...
=============================================================================
#include <iostream> // std::cout
#include <ostream> // <<, std::endl
template< typename Id_ >
class MutableMember_
{
protected:
typedef typename Id_::Type Type;
MutableMember_(): myMember() {}
MutableMember_( Type const& value ): myMember( value ) {}
virtual void onUpdate( Id_, Type& ) const {}
void update( Id_ id ) const { onUpdate( id, myMember ); }
Type& member( Id_ ) { return myMember; }
Type const& member( Id_ ) const { return myMember; }
private:
mutable Type myMember;
};
struct Person_Age { typedef int Type; };
class Person: protected MutableMember_<Person_Age>
{
protected:
virtual void onUpdate( Person_Age, Person_Age::Type& age ) const
{
if( age == -1 ) { age = 42; } // Simulate a database read.
}
public:
Person(): MutableMember_<Person_Age>( -1 ) {}
Person_Age::Type age() const
{
update( Person_Age() );
return member( Person_Age() );
}
void celebrateBirthdate()
{
++member( Person_Age() );
}
};
int main()
{
Person olga;
std::cout << olga.age() << std::endl;
std::cout << olga.age() << std::endl;
olga.celebrateBirthdate();
std::cout << olga.age() << std::endl;
}
=============================================================================
42
42
43
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Jerry Coffin" <jcoffin@taeus.com>
Date: Mon, 11 Apr 2005 10:07:02 CST Raw View
Andre Caldas wrote:
[ ... ]
> Sorry if I am wrong here. But in this case, please explain me what
> "mutable members" are.
A common use for mutable members is caching a value (or set of values)
that is/are expensive to calculate, but which don't affect the logical
state of the object. For example, assume you have a few million numbers
in a set and you can compute typical statistics on them (mean, standard
deviation, etc.) The logical state of the object is that set of numbers
-- but if you read through the numbers to compute the mean, you don't
want to do it all over again to compute the standard deviation.
The cure is to compute all your statisctics the first time through, and
cache the resulting values in mutable members, so when the user asks
for another of them, you just return it.
--
Later,
Jerry.
The universe is figment of its own imagination.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: wade@stoner.com
Date: Mon, 11 Apr 2005 10:07:49 CST Raw View
Dave Harris wrote:
> wade@stoner.com () wrote (abridged):
> > const_cast<T*>(this)->m_foo = bar;
> >
> > The only time the compiler "knows" I don't have that line is
> > 1) The compiler can see the source code of my method or
> > 2) The compiler can see (or infer) the definition of my object
(not
> > just the definition of a pointer or reference to my object) and
> > 2a) the definition says my object is const and not on the heap
and
> > 2b) the compiler knows my method is not being called directly
or
> > indirectly from a constructor/destructor of my object (or of a
larger
> > object that contains my object as a sub-object).
>
> Are you sure that heap-allocated const objects are the exception you
note
> in 2a) ?
It is UB to modify a const object during its lifetime.
3.8/9 says that it is UB to create a new object at the location of "...
a const object with static or automatic storage duration ...". There
is a strong implication that it is acceptable to create a new object at
the location of a const heap object.
const int *p = new const int(42);
void* pv = const_cast<int*>(p);
new(pv) const int(54);
seems to be legal. Unless the compiler knows that I don't do this
(which typically means seeing the source) it can't assume that *p is
immutable across function calls.
>
> I would have said this:
>
> const int *p = new const int(42);
> *const_cast<int *>(p) = 54; // ??
>
> had undefined behaviour.
It probably does, according to the letter of the standard. However,
since a well-formed program can get the same effect with placement new,
it is difficult for an optimizing compiler to use that to its
advantage.
Also note that if operator new() was written by the programmer, it may
have left non-const aliases to the address which it returned.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: meang@post.com (Meang Akira Tanaka)
Date: Mon, 11 Apr 2005 23:20:28 GMT Raw View
On Mon, 11 Apr 2005 03:53:36 GMT, andre@ba-z.co.jp (Andre Caldas)
wrote:
>Sorry, Tanaka-san!
No problem Caldas-san
>I am really new to "mutable members", but I don't think this is their
>purpose.
The standard ISO14882 states the following:
7.1.1
The mutable specifier on a class data member nullifies a const
specifier applied to the containing class object amd permits
modification of the mutable class member even though the rest of the
object is const(7.1.5.1)
One can only interpret what this can be used for since the standard
probably doesn't indicates the usage (I haven't read the whole spec,
so I guest this is a claim)
but I interpret this as it can be used for following pupose:
As indicated by Jerry Coffin a way to optimize by letting all
methods to alter these members. What I have against mutable members
is that all methods const and non-const are able to alter these data.
I would suggest that only designated methods should alter the state of
the instance rather than all methods.
hope that helped.
br
Meang
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: andre@ba-z.co.jp (Andre Caldas)
Date: Tue, 19 Apr 2005 01:58:47 GMT Raw View
> At least as I understand the proposal, it's that most const member
> functions would not be able to alter even mutable member variables --
> rather, the function would have to be designated as (apparently) 'const
> mutable' to be able to alter mutable member variables.
I think this is the only meaningfull way something like a "mutable
function" could be defined.
> I'll add that I may have misunderstood your question
Never mind. I do that all the time. ;-)
> I certainly was not
> trying to defend or advocate for mutable member functions -- in fact, I
> think they're a bad idea.
Good.
> IOW, the current situation is a fine example of
> encapsulation/information hiding, and making mutable part of a function
> signature would break that.
And it would also give people lots of headaches for no good reason.
Andre Caldas.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: meang@post.com (Meang Akira Tanaka)
Date: Fri, 1 Apr 2005 23:22:55 GMT Raw View
On Mon, 28 Mar 2005 18:29:50 CST, alfps@start.no (Alf P. Steinbach)
wrote:
>[snip]
>Simply inherit from the following class, one or more times, where 'Id_'
>is some dummy type that you define as a name for the member in question:
>
> template< typename Id_, class MemberType_ >
> class MutableMemberRef_
> {
> private:
> MemberType_* myMemberPtr;
>
> protected:
> MutableMemberRef_( MemberType_* aMemberPtr ):
> myMemberPtr( aMemberPtr )
> {}
>
> virtual void onGet( Id_, MemberType_& ) const {}
>
> MemberType_& get( Id_ ) const
> {
> onGet( Id_(), *myMemberPtr );
> return *myMemberPtr;
> }
> };
But that is basically the two class solution so you have separeted the
data from the actual logic. But wasn't the intend of OO to tie the
actual logic with the data rather than separating those
br
Meang.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Yuriy Solodkyy <solodon@tamu.put_edu_here>
Date: Sat, 2 Apr 2005 00:39:59 CST Raw View
Just checked the standard on this point, my assumption was indeed wrong.
If anyone is interested, here there are some more explanations on the
issue including why compiler almost never can take constness of the
method into account for optimization purposes:
http://new-brunswick.net/workshop/c++/faq/const-correctness.html#faq-18.7
But then I still don't understand the purpose of mutable members.
Yuriy
wade@stoner.com wrote:
> I'm ignoring 'mutable' members in the following:
>
> YS said that compilers may assume that calls to const methods don't
> modify the underlying object. I disaggree.
>
> FG said that you can't remove 'const' from references or pointers to
> const objects. I disagree slightly: you can remove the const, you just
> can't modify the object. However I agree with the implication that
> compilers may assume that nothing modifies const objects (an entirely
> different assumption from YS's).
>
> I (BW) said that if the compiler can't see the source of the method,
> YS's statement is true only when the compiler knows
> -- The underlying object is const (and not on the heap). Pretty much
> what FG said.
>
> By example:
>
> struct foo
> {
> int m_bar;
> void FooBar() const { const_cast<foo*>(this)->m_bar = EXIT_FAILURE; }
> };
>
> int main()
> {
> foo f;
> f.m_bar = EXIT_SUCCESS;
> f.FooBar(); // Call a const method on a non-const object
> return f.m_bar;
> }
>
> YS's statement would mean that the result is unpredictable because the
> compiler might (or might not) assume that f.m_bar cannot be modified by
> the call to the const function.
>
> I say that the program is well defined and must return EXIT_FAILURE.
> In particular, no attempt was made to modify a const object. There is
> nothing in the standard that allows the compiler to make the
> inappropriate optimization.
>
> ---
> [ comp.std.c++ is moderated. To submit articles, try just posting with ]
> [ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
> [ --- Please see the FAQ before posting. --- ]
> [ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
>
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: meang@post.com (Meang Akira Tanaka)
Date: Mon, 4 Apr 2005 05:19:40 GMT Raw View
[*snip*]
>But then I still don't understand the purpose of mutable members.
>
>Yuriy
>
Basically for having a single or few method which are doing "dirty"
work rather than spreading it all over the code.
br
Meang
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: 4 Apr 2005 12:55:01 GMT Raw View
* Meang Akira Tanaka:
> On Mon, 28 Mar 2005 18:29:50 CST, alfps@start.no (Alf P. Steinbach)
> wrote:
>
> >[snip]
> >Simply inherit from the following class, one or more times, where 'Id_'
> >is some dummy type that you define as a name for the member in question:
> >
> > template< typename Id_, class MemberType_ >
> > class MutableMemberRef_
> > {
> > private:
> > MemberType_* myMemberPtr;
> >
> > protected:
> > MutableMemberRef_( MemberType_* aMemberPtr ):
> > myMemberPtr( aMemberPtr )
> > {}
> >
> > virtual void onGet( Id_, MemberType_& ) const {}
> >
> > MemberType_& get( Id_ ) const
> > {
> > onGet( Id_(), *myMemberPtr );
> > return *myMemberPtr;
> > }
> > };
>
> But that is basically the two class solution
?
> so you have separeted the data from the actual logic.
?
> But wasn't the intend of OO to tie the actual logic with the data
> rather than separating those
?
Ignoring the issue of accessing a non-mutable member this way (addressed
in my own follow-up), in what way doesn't this fix your problem?
Exactly what _is_ the original problem then?
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Nicola Musatti" <nicola.musatti@gmail.com>
Date: Tue, 5 Apr 2005 13:32:27 CST Raw View
Meang Akira Tanaka wrote:
[...]
> 1. Two class solution
>
> One class that contains the data and is read, the other one contains
> all the logic.
>
> Drawback: the data is separated from the logic, which in my humble
> opinion would be a step back from OO design.
I do not agree. Separating the logic model from the persistence
infrastructure improves the OO design because you separate the
representation of a portion of the real world from low level details.
Do you really think that a BankAccount class should have a
readFromOracle() and a writeToOracle() member functions?
This is particularly important when you deal with complex entities,
which otherwise would result in unmanageable classes.
Cheers,
Nicola Musatti
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: andre@ba-z.co.jp (Andre Caldas)
Date: Tue, 12 Apr 2005 09:50:18 GMT Raw View
>>Sorry, Tanaka-san!
> No problem Caldas-san
Please, call me "Andore(-san)"! ;-)
> I would suggest that only designated methods should alter the state of
> the instance rather than all methods.
If it is:
* only "mutable methods" can change the value of "mutable variables"
then that would be new.
But if it is:
* "Mutable methods" can change the value of any "member variable", then
you could get this behaviour by using a "const_cast" *inside* this so
called "mutable method" of yours.
ie:
void
A::Mutable_Method (void) const
{
A* This = const_cast<A*>(this);
//Use "This" whenever you want to change the object.
}
Andre Caldas.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: bop@gmb.dk ("Bo Persson")
Date: Wed, 13 Apr 2005 02:22:17 GMT Raw View
"Meang Akira Tanaka" <meang@post.com> skrev i meddelandet
news:ju6l511amnugg296auk99n6jqqft220cvu@4ax.com...
> On Mon, 11 Apr 2005 03:53:36 GMT, andre@ba-z.co.jp (Andre Caldas)
> wrote:
>
> The standard ISO14882 states the following:
>
> 7.1.1
>
> The mutable specifier on a class data member nullifies a const
> specifier applied to the containing class object amd permits
> modification of the mutable class member even though the rest of the
> object is const(7.1.5.1)
>
> One can only interpret what this can be used for since the standard
> probably doesn't indicates the usage (I haven't read the whole spec,
> so I guest this is a claim)
>
> but I interpret this as it can be used for following pupose:
>
> As indicated by Jerry Coffin a way to optimize by letting all
> methods to alter these members. What I have against mutable members
> is that all methods const and non-const are able to alter these data.
>
> I would suggest that only designated methods should alter the state of
> the instance rather than all methods.
The idea is to use mutable members for values that does not change the
logical (or visible) state of an instance. They could, for example, be
used to cache the value of an expensive calculation.
Bo Persson
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Andre Caldas <andre@ba-z.co.jp>
Date: Tue, 12 Apr 2005 23:58:20 CST Raw View
Jerry Coffin wrote:
> A common use for mutable members is caching a value (or set of values)
> that is/are expensive to calculate, but which don't affect the logical
> state of the object. For example, assume you have a few million numbers
> in a set and you can compute typical statistics on them (mean, standard
> deviation, etc.) The logical state of the object is that set of numbers
> -- but if you read through the numbers to compute the mean, you don't
> want to do it all over again to compute the standard deviation.
>
> The cure is to compute all your statisctics the first time through, and
> cache the resulting values in mutable members, so when the user asks
> for another of them, you just return it.
Thanks for making my point.
So, a "mutable member variable" is about a change in the internal state
of the object, but that in fact is invisible to the outside world. What
would be the proposed "mutable member function"?
Andre Caldas.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Jerry Coffin" <jcoffin@taeus.com>
Date: Wed, 13 Apr 2005 09:54:14 CST Raw View
Andre Caldas wrote:
[ ... ]
> Thanks for making my point.
Surely.
> So, a "mutable member variable" is about a change in the internal
> state of the object, but that in fact is invisible to the outside
> world. What would be the proposed "mutable member function"?
At least as I understand the proposal, it's that most const member
functions would not be able to alter even mutable member variables --
rather, the function would have to be designated as (apparently) 'const
mutable' to be able to alter mutable member variables.
I'll add that I may have misunderstood your question -- I thought you
were asking about the point of mutable member variables (perhaps a
result of not having read the entire thread). I certainly was not
trying to defend or advocate for mutable member functions -- in fact, I
think they're a bad idea.
The whole point of a mutable variable is that changing its value does
NOT alter the state of the object. As such, the outside world should
not be concerned that it even exists, not to mention caring what might
change it, under what circumstances, etc.
IOW, the current situation is a fine example of
encapsulation/information hiding, and making mutable part of a function
signature would break that.
--
Later,
Jerry.
The universe is a figment of its own imagination.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: meang@post.com (Meang Akira Tanaka)
Date: Mon, 28 Mar 2005 00:34:29 GMT Raw View
Hi
In connection with my work where data is read from the database. It
hasn't always been optimal to read all the data associated to an
object from the database.
A way to optimize this is to introduce the concept of lazy read. But
the idea is that only an id is set in the class and when necessary the
rest is read to the object(typically in getters). However typically in
getters const is applied and therefore an issue regarding constness
will happen.
In order to solve this several solutions exists:
1. Two class solution
One class that contains the data and is read, the other one contains
all the logic.
Drawback: the data is separated from the logic, which in my humble
opinion would be a step back from OO design.
2. const_cast solution
One could const cast the this pointer and then invoke a non-const
method.
Drawback: doesn't look nice when reading through the code.
3. Mutable members
One could make the members mutable.
Drawback: all other functions even if they guarantee constness can
alter these.
4. Mutable methods.
C++ could give the mutable keyword a meaning for methods.
My idea was that mutable methods are able to be called within const
methods and mutable methods are able to alter the state of the object.
The advantage of this approach is that not all methods are able to
alter the state of the object as in solution 3, no need for const
cast, and the data and the logic is kept together.
Do anyone have an opnion about this suggestion
Br
Meang
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Yuriy Solodkyy <solodon@tamu.put_edu_here>
Date: Mon, 28 Mar 2005 00:47:34 CST Raw View
Can you clarify which members can a mutable member function modify: all
or only mutable?
If only mutable, then I don't see the point in declaring method as
mutable, as it can be declared as const and hence be called from other
const methods.
If it can change any member, then I think we loose the point for which
const declarations were introduced. By making a method const you give
compiler information that content of the object won't be changed by a
call to such method and that it can apply appropriate optimizations in
accessing any non-mutable attribute. By allowing calls that basically
can change content of the object from within const method, compiler
wouldn't be able to assume anymore that content is not changed and hence
avoid any optimization.
If we'll think of method
int C::method(int) const
as a global function
int C_method(const C*, int)
what will be the meaning of information you give to compiler by stating:
int C_method(mutable C*, int)
?
Remember that in C++ definition of the method is not always available at
the point of usage of this method (e.g. you've got header and lib file
only) so it can not try to figure out himself what is changed by the
method and what is not. Also C++ compiler works independently with
translation units and doesn't have to keep information in between
compilations of different translation units.
Sorry if I didn't understand you right.
Yuriy
Meang Akira Tanaka wrote:
> Hi
>
> In connection with my work where data is read from the database. It
> hasn't always been optimal to read all the data associated to an
> object from the database.
>
> A way to optimize this is to introduce the concept of lazy read. But
> the idea is that only an id is set in the class and when necessary the
> rest is read to the object(typically in getters). However typically in
> getters const is applied and therefore an issue regarding constness
> will happen.
>
> In order to solve this several solutions exists:
>
> 1. Two class solution
>
> One class that contains the data and is read, the other one contains
> all the logic.
>
> Drawback: the data is separated from the logic, which in my humble
> opinion would be a step back from OO design.
>
> 2. const_cast solution
>
> One could const cast the this pointer and then invoke a non-const
> method.
>
> Drawback: doesn't look nice when reading through the code.
>
> 3. Mutable members
>
> One could make the members mutable.
>
> Drawback: all other functions even if they guarantee constness can
> alter these.
>
> 4. Mutable methods.
>
> C++ could give the mutable keyword a meaning for methods.
>
> My idea was that mutable methods are able to be called within const
> methods and mutable methods are able to alter the state of the object.
>
> The advantage of this approach is that not all methods are able to
> alter the state of the object as in solution 3, no need for const
> cast, and the data and the logic is kept together.
>
> Do anyone have an opnion about this suggestion
>
> Br
>
> Meang
>
> ---
> [ comp.std.c++ is moderated. To submit articles, try just posting with ]
> [ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
> [ --- Please see the FAQ before posting. --- ]
> [ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
>
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Mon, 28 Mar 2005 18:29:50 CST Raw View
* Meang Akira Tanaka:
>
[snip]
>
> 4. Mutable methods.
>
> C++ could give the mutable keyword a meaning for methods.
>
> My idea was that mutable methods are able to be called within const
> methods and mutable methods are able to alter the state of the object.
>
> The advantage of this approach is that not all methods are able to
> alter the state of the object as in solution 3, no need for const
> cast, and the data and the logic is kept together.
>
> Do anyone have an opnion about this suggestion
Simply inherit from the following class, one or more times, where 'Id_'
is some dummy type that you define as a name for the member in question:
template< typename Id_, class MemberType_ >
class MutableMemberRef_
{
private:
MemberType_* myMemberPtr;
protected:
MutableMemberRef_( MemberType_* aMemberPtr ):
myMemberPtr( aMemberPtr )
{}
virtual void onGet( Id_, MemberType_& ) const {}
MemberType_& get( Id_ ) const
{
onGet( Id_(), *myMemberPtr );
return *myMemberPtr;
}
};
In your derived class, override 'onGet' as appropriate.
Disclaimer: I wrote this just to reply to this posting, so it's not been honed
by real-world usage. Insight: now that I think of it, it seems to make
'mutable' of negative value! Wish: a new language feature so that a class
nested in class X can be used in the inheritance list of class X.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Meang Akira Tanaka <meang@post.com>
Date: Mon, 28 Mar 2005 18:30:30 CST Raw View
>Can you clarify which members can a mutable member function modify: all
>or only mutable?
a mutable member function should be allowed to alter all members
except for those inherited private members. i.e. the access rules
still apply.
>If it can change any member, then I think we loose the point for which
>const declarations were introduced.
You are definitly right that we may loose the point in constness of a
function but I think we already lost some with the introduction of
mutable keyword, so I guess my suggestion is in the same league as
mutable on attributes. But I guess I hope that mutable function will
give somewhat a cleaner design than having mutable members.
As far as I remember the ANSI ISO/IEC 14882 (First edition 1998-09-01)
Section 7.1.1 states the following:
"The mutable specifier on a class data member nullifies a const
specifier applied to the containing class object and permits
modification of the mutable class member even though the rest of the
object is const (7.1.5.1)"
The way I interpret this section is that mutable attributes are a
workaround for functions which are declared const to alter the state
of the instance.
And I see the section in the ANSI standard as an acknowledgment that
even if const correctness should be applied where applicable there are
situation where constness conflicts in the way programs are designed.
and especially when optimization is an issue. One could maybe argue
that the design is wrong somehow, but if anyone can come up with a
good solution on how to ensure that data is only read when necessary I
am all ears.
In cases where programs have to read its state from some source, and
the reading takes longer time that accepted. It will need to be
optimized some way or another I guess one of the most common ways are
to only read those things that are needed.
My suggestion is that following should be possible:
class A
{
private
int mAttribute;
int mId;
int getAttribute() const
{
lazyRead();
return mAttribute;
}
void lazyRead() mutable
{
if(!read)
{
... read...
mAttribute = 12;
read = true;
}
}
Const method should be allowed to invoke const and mutable functions.
in this example getAttribute may invoke lazyRead which is able to
alter the state.
Why is this better than the other solution I have mentioned?
Well the arguments are following (I've added some more concrete
examples on what the alternatives are in the end of the mail):
1. Separating clean code from some code that is a workaround due to
optimization. (i.e. By having a method that are able to modify
attributes instead of doing a const_cast and then invoking a non-const
method).
2. You ensure that only designated members are allowed
to alter the state (as opposed to all members when using the mutable
keyword)
3. You ensure that code and logic are tied together (as opposed to try
to avoiding constness by separating the code from data)
The following examples may illustrate more clearly the issues:
Mutable attributes Solution:
class A
{
private
mutable int mAttribute;
mutable int mId;
int getAttribute() const
{
read();
return mAttribute;
}
void read() const
{
if(!read)
{
... read...
mAttribute = 12;
read = true;
}
}
The mutable solution means that any member can modify mAttribute and
mId, which basically means that constness effectively is removed.
Mutable functions still retains the value of constness.
Two class solution:
class A
{
private
B *mImpl;
A::A()
{
mImpl = new B();
}
int getAttribute() const
{
read();
return mAttribute;
}
void read() const
{
if(!read)
{
... set attribute...
mImpl->setAttribute(12);
read = true;
}
}
class B
{
private
int mAttribute;
int mId;
int getAttribute() const
{
return mAttribute;
}
}
The two class solution separes the logic from the data. which is the
opposite idea of what object-oriented strives too. Therefore in my
humble opinion not good solution.
The const_cast solution is as follows:
class A
{
private
int mAttribute;
int mId;
int getAttribute() const
{
A* ptr = const_cast<A>(this);
ptr->read();
return mAttribute;
}
void read()
{
if(!read)
{
... read...
mAttribute = 12;
read = true;
}
}
The const_cast solution is somewhat ugly. First this pointer is const
cast in order to remove const then a non-const method is invoked.
>By allowing calls that basically
>can change content of the object from within const method, compiler
>wouldn't be able to assume anymore that content is not changed and hence
>avoid any optimization.
You are right It cannot assume that the method cannot be changed (I
didn't thought of that). But wouldn't the same argument apply to
mutable attributes? Can the compiler safely assume that content when
invoking a const method which has mutable attributes?
>Sorry if I didn't understand you right.
>
I'm apologize if I haven't been concise enough
br
Meang
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: wade@stoner.com
Date: Mon, 28 Mar 2005 18:31:16 CST Raw View
Yuriy Solodkyy wrote:
> ... By making a method const you give
> compiler information that content of the object won't be changed by a
> call to such method and that it can apply appropriate optimizations
.
Typically you aren't telling the compiler that much. The compiler
still has to consider that my const method might have a line like
const_cast<T*>(this)->m_foo = bar;
The only time the compiler "knows" I don't have that line is
1) The compiler can see the source code of my method or
2) The compiler can see (or infer) the definition of my object (not
just the definition of a pointer or reference to my object) and
2a) the definition says my object is const and not on the heap and
2b) the compiler knows my method is not being called directly or
indirectly from a constructor/destructor of my object (or of a larger
object that contains my object as a sub-object).
For both (1) and (2), the declaration of 'const' on the method makes no
difference. If either (1) or (2) applies, the compiler can perform the
optimization.
The purpose of 'const' on methods is to document the programmer's
intent. A side benefit is that this gives code reviewers (including
compilers) a chance to tell him when he messed up.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Wed, 30 Mar 2005 02:36:56 GMT Raw View
In article <1112024258.895473.322000@l41g2000cwc.googlegroups.com>,
wade@stoner.com writes
>Typically you aren't telling the compiler that much. The compiler
>still has to consider that my const method might have a line like
>
> const_cast<T*>(this)->m_foo = bar;
No, it does not and that is one reason that the mutable keyword was
introduced. It is undefined behaviour to attempt to remove a const
qualification from an object (i.e. the underlying object was declared as
const). The purpose of a const_cast is to support removing a conts
qualification from a reference (or pointer) when the referenced object
(or the pointed to object) was not itself declared as const.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Wed, 30 Mar 2005 12:55:25 GMT Raw View
* Alf P. Steinbach:
> [description of class MutableMemberRef_]
After reading Francis Glassborow's response elsewhere in the thread it
became clear to me that this should instead be a class MutableMember_, with a
'mutable' member... ;-)
Otherwise it could be very very dangerous.
With that change, and perhaps a virtual 'update' function instead of
'onGet', I think it implements the OP's wishes w/o extending the language.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: wade@stoner.com
Date: Wed, 30 Mar 2005 19:17:55 CST Raw View
I'm ignoring 'mutable' members in the following:
YS said that compilers may assume that calls to const methods don't
modify the underlying object. I disaggree.
FG said that you can't remove 'const' from references or pointers to
const objects. I disagree slightly: you can remove the const, you just
can't modify the object. However I agree with the implication that
compilers may assume that nothing modifies const objects (an entirely
different assumption from YS's).
I (BW) said that if the compiler can't see the source of the method,
YS's statement is true only when the compiler knows
-- The underlying object is const (and not on the heap). Pretty much
what FG said.
By example:
struct foo
{
int m_bar;
void FooBar() const { const_cast<foo*>(this)->m_bar = EXIT_FAILURE; }
};
int main()
{
foo f;
f.m_bar = EXIT_SUCCESS;
f.FooBar(); // Call a const method on a non-const object
return f.m_bar;
}
YS's statement would mean that the result is unpredictable because the
compiler might (or might not) assume that f.m_bar cannot be modified by
the call to the const function.
I say that the program is well defined and must return EXIT_FAILURE.
In particular, no attempt was made to modify a const object. There is
nothing in the standard that allows the compiler to make the
inappropriate optimization.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]