Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #7665 > unrolled thread
| Started by | Qi <no@no.com> |
|---|---|
| First post | 2011-07-09 14:19 +0800 |
| Last post | 2011-07-09 16:54 +0800 |
| Articles | 15 — 8 participants |
Back to article view | Back to comp.lang.c++
mutable vs const_cast, which is better to modify field from const function? Qi <no@no.com> - 2011-07-09 14:19 +0800
Re: mutable vs const_cast, which is better to modify field from const function? Narinder <narinder.claire@gmail.com> - 2011-07-09 00:20 -0700
Re: mutable vs const_cast, which is better to modify field from const function? Qi <no@no.com> - 2011-07-09 15:50 +0800
Re: mutable vs const_cast, which is better to modify field from const function? Narinder <narinder.claire@gmail.com> - 2011-07-09 01:36 -0700
Re: mutable vs const_cast, which is better to modify field from const function? Ian Collins <ian-news@hotmail.com> - 2011-07-09 19:28 +1200
Re: mutable vs const_cast, which is better to modify field from const function? Qi <no@no.com> - 2011-07-09 15:56 +0800
Re: mutable vs const_cast, which is better to modify field from const function? Ian Collins <ian-news@hotmail.com> - 2011-07-09 20:04 +1200
Re: mutable vs const_cast, which is better to modify field from const function? Narinder <narinder.claire@gmail.com> - 2011-07-12 15:41 -0700
Re: mutable vs const_cast, which is better to modify field from const function? SG <s.gesemann@gmail.com> - 2011-07-09 01:25 -0700
Re: mutable vs const_cast, which is better to modify field from const function? Werner Erasmus <werasm@gmail.com> - 2011-07-10 22:25 +0200
Re: mutable vs const_cast, which is better to modify field from const function? Qi <no@no.no> - 2011-07-11 09:54 +0800
Re: mutable vs const_cast, which is better to modify field from const function? Werner Erasmus <werasm@gmail.com> - 2011-07-11 09:08 +0200
Re: mutable vs const_cast, which is better to modify field from const function? Paavo Helde <myfirstname@osa.pri.ee> - 2011-07-09 03:31 -0500
Re: mutable vs const_cast, which is better to modify field from const function? "Balog Pal" <pasa@lib.hu> - 2011-07-09 10:47 +0200
Re: mutable vs const_cast, which is better to modify field from const function? Qi <no@no.com> - 2011-07-09 16:54 +0800
| From | Qi <no@no.com> |
|---|---|
| Date | 2011-07-09 14:19 +0800 |
| Subject | mutable vs const_cast, which is better to modify field from const function? |
| Message-ID | <iv8s22$2sp$1@speranza.aioe.org> |
It's not rare to lazy initialize member field in getter functions which
are const function.
class SomeClass {
public:
MyObject * getMyObject() const {
if(! this->myObject) {
this->myObject = create the object;
}
return this->myObject;
}
private:
MyObject * myObject;
};
To be able to modify myObject in the getter function, we can
either,
1, Use mutable on myObject.
mutable MyObject * myObject;
or
2, Use const_cast to cast away constness from "this".
const_cast<SomeClass *>(this)->myObject = create the object;
Both methods have their own pros and cons, that's why I can't
decide which is better.
Method 1 (mutable),
Pros:
It's quite nature. Since myObject can be modified by a
const function, it's natural that it's mutable.
Cons:
A, "mutable" makes myObject to be changable to all const
functions. This is the problem. It should not be able to be
modified by any const functions except the lazy initialization
(the getter).
B, Any one reading the code may misunderstand that myObject
is really mutable while it's not.
Method 2 (const_cast),
Pros:
The effect is only limited to the getter function, any other
const functions can't modify myObject.
Cons:
A, Casting a const "this" to non-const looks so ugly and not
natural.
B, And a const function being able to modify a non-mutable member
is not natural too.
My questions:
1, Which method do you prefer to implement lazy initialization?
2, I think both methods are quite standard C++ (03), right?
If not, please point out.
Thanks
--
WQ
[toc] | [next] | [standalone]
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-07-09 00:20 -0700 |
| Message-ID | <0a3d5245-a6d6-4b11-bf09-ae3f80333e44@h8g2000yqj.googlegroups.com> |
| In reply to | #7665 |
On Jul 9, 7:19 am, Qi <n...@no.com> wrote:
> It's not rare to lazy initialize member field in getter functions which
> are const function.
>
> class SomeClass {
> public:
> MyObject * getMyObject() const {
> if(! this->myObject) {
> this->myObject = create the object;
> }
>
> return this->myObject;
> }
>
> private:
> MyObject * myObject;
>
> };
>
> To be able to modify myObject in the getter function, we can
> either,
> 1, Use mutable on myObject.
> mutable MyObject * myObject;
> or
> 2, Use const_cast to cast away constness from "this".
> const_cast<SomeClass *>(this)->myObject = create the object;
>
> Both methods have their own pros and cons, that's why I can't
> decide which is better.
>
> Method 1 (mutable),
> Pros:
> It's quite nature. Since myObject can be modified by a
> const function, it's natural that it's mutable.
>
> Cons:
> A, "mutable" makes myObject to be changable to all const
> functions. This is the problem. It should not be able to be
> modified by any const functions except the lazy initialization
> (the getter).
> B, Any one reading the code may misunderstand that myObject
> is really mutable while it's not.
>
> Method 2 (const_cast),
> Pros:
> The effect is only limited to the getter function, any other
> const functions can't modify myObject.
>
> Cons:
> A, Casting a const "this" to non-const looks so ugly and not
> natural.
> B, And a const function being able to modify a non-mutable member
> is not natural too.
>
> My questions:
> 1, Which method do you prefer to implement lazy initialization?
> 2, I think both methods are quite standard C++ (03), right?
> If not, please point out.
>
> Thanks
>
> --
> WQ
Deviating as little as possible from your code and addressing ONLY
your question, here is my suggestion:
-------------------------------------------
struct MyObject{};
struct SomeClass
{
SomeClass():myObject(0){}
const MyObject * getMyObject()const
{
return getMyObject_impl();
}
MyObject * getMyObject()
{
return getMyObject_impl();
}
private:
const MyObject * getMyObject_impl()const
{
if(!myObject)
{
myObject = new MyObject();
}
return myObject;
}
MyObject * getMyObject_impl()
{
if(!myObject)
{
myObject = new MyObject();
}
return myObject;
}
mutable MyObject * myObject;
};
-------------------------------------------------
So as long as all your other member functions access myObject via the
getMyObject_impl methods it should be ok.
Rgds
N
[toc] | [prev] | [next] | [standalone]
| From | Qi <no@no.com> |
|---|---|
| Date | 2011-07-09 15:50 +0800 |
| Message-ID | <iv91dr$fjl$1@speranza.aioe.org> |
| In reply to | #7667 |
On 2011-7-9 15:20, Narinder wrote:
> struct MyObject{};
>
> struct SomeClass
> {
> SomeClass():myObject(0){}
>
> const MyObject * getMyObject()const
> {
> return getMyObject_impl();
> }
>
> MyObject * getMyObject()
> {
> return getMyObject_impl();
> }
>
> private:
>
> const MyObject * getMyObject_impl()const
> {
> if(!myObject)
> {
> myObject = new MyObject();
>
> }
> return myObject;
> }
>
> MyObject * getMyObject_impl()
> {
> if(!myObject)
> {
> myObject = new MyObject();
>
> }
> return myObject;
> }
>
> mutable MyObject * myObject;
> };
>
> -------------------------------------------------
>
>
> So as long as all your other member functions access myObject via the
> getMyObject_impl methods it should be ok.
First, sorry that I forgot the "const" in the return of the getter.
I did mean const MyObject * getMyObject()const.
Back to my question, seems you are suggesting to use "mutable", right?
--
WQ
[toc] | [prev] | [next] | [standalone]
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-07-09 01:36 -0700 |
| Message-ID | <47ecb255-c947-48b1-a14f-991139948c35@s2g2000vbw.googlegroups.com> |
| In reply to | #7669 |
On Jul 9, 8:50 am, Qi <n...@no.com> wrote:
> On 2011-7-9 15:20, Narinder wrote:
>
>
>
>
>
>
>
>
>
> > struct MyObject{};
>
> > struct SomeClass
> > {
> > SomeClass():myObject(0){}
>
> > const MyObject * getMyObject()const
> > {
> > return getMyObject_impl();
> > }
>
> > MyObject * getMyObject()
> > {
> > return getMyObject_impl();
> > }
>
> > private:
>
> > const MyObject * getMyObject_impl()const
> > {
> > if(!myObject)
> > {
> > myObject = new MyObject();
>
> > }
> > return myObject;
> > }
>
> > MyObject * getMyObject_impl()
> > {
> > if(!myObject)
> > {
> > myObject = new MyObject();
>
> > }
> > return myObject;
> > }
>
> > mutable MyObject * myObject;
> > };
>
> > -------------------------------------------------
>
> > So as long as all your other member functions access myObject via the
> > getMyObject_impl methods it should be ok.
>
> First, sorry that I forgot the "const" in the return of the getter.
> I did mean const MyObject * getMyObject()const.
>
> Back to my question, seems you are suggesting to use "mutable", right?
>
> --
> WQ
>seems you are suggesting to use "mutable", right?
Yes I am, but at the same time if it's only ever accessed via the
private impl methods than effectively it's not mutable for your other
member functions. I would stay away from const_cast, I use it only in
debug specific code ( eg to make certain views available into const
data type to the debugger).
In the end you want your pointer to be mutable only for the
initialiser method, so, make it only mutable for the initialiser
method, which in my case are the private impl methods.
You could go one step further and encompass your pointer in a class
of it's own.
------------------------------------------
struct MyObject{};
struct MyObjectWrapper
{
MyObjectWrapper():myObject(0){}
const MyObject * getMyObject_impl()const
{
if(!myObject)
{
myObject = new MyObject();
}
return myObject;
}
MyObject * getMyObject_impl()
{
if(!myObject)
{
myObject = new MyObject();
}
return myObject;
}
private:
mutable MyObject * myObject;
};
struct SomeClass
{
const MyObject * getMyObject()const
{
return myObject.getMyObject_impl();
}
MyObject * getMyObject()
{
return myObject.getMyObject_impl();
}
private:
MyObjectWrapper myObject;
};
------------------------------------------
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2011-07-09 19:28 +1200 |
| Subject | Re: mutable vs const_cast, which is better to modify field from const function? |
| Message-ID | <97qea4F6tmU2@mid.individual.net> |
| In reply to | #7665 |
On 07/ 9/11 06:19 PM, Qi wrote:
> It's not rare to lazy initialize member field in getter functions which
> are const function.
>
> class SomeClass {
> public:
> MyObject * getMyObject() const {
> if(! this->myObject) {
> this->myObject = create the object;
> }
>
> return this->myObject;
> }
You don't need all those "this->".
> private:
> MyObject * myObject;
> };
>
> To be able to modify myObject in the getter function, we can
> either,
> 1, Use mutable on myObject.
> mutable MyObject * myObject;
> or
> 2, Use const_cast to cast away constness from "this".
> const_cast<SomeClass *>(this)->myObject = create the object;
>
> Both methods have their own pros and cons, that's why I can't
> decide which is better.
How about:
struct SomeClass
{
SomeClass() {}
MyObject* getMyObject() const
{
static MyObject* myObject;
if(!myObject)
{
myObject = new MyObject;
}
return myObject;
}
};
--
Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | Qi <no@no.com> |
|---|---|
| Date | 2011-07-09 15:56 +0800 |
| Subject | Re: mutable vs const_cast, which is better to modify field from const function? |
| Message-ID | <iv91p9$fjl$2@speranza.aioe.org> |
| In reply to | #7668 |
On 2011-7-9 15:28, Ian Collins wrote:
>> MyObject * getMyObject() const {
>> if(! this->myObject) {
>> this->myObject = create the object;
>> }
>>
>> return this->myObject;
>> }
>
> You don't need all those "this->".
That's my personal style. I like those "this->"
because it makes members more obvious, if not considering
ADL. I used that style in all my C++, Java, Action Script
code.
Hope we stop here because that topic is quite subjective
and off topic. :-)
> How about:
>
> struct SomeClass
> {
> SomeClass() {}
>
> MyObject* getMyObject() const
> {
> static MyObject* myObject;
>
> if(!myObject)
> {
> myObject = new MyObject;
> }
>
> return myObject;
> }
> };
That's another method.
But I do want myObject be member data so other functions
may check "myObject == NULL" when initialization is not
required.
--
WQ
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2011-07-09 20:04 +1200 |
| Subject | Re: mutable vs const_cast, which is better to modify field from const function? |
| Message-ID | <97qgdgF6tmU3@mid.individual.net> |
| In reply to | #7670 |
On 07/ 9/11 07:56 PM, Qi wrote:
> On 2011-7-9 15:28, Ian Collins wrote:
>
>> How about:
>>
>> struct SomeClass
>> {
>> SomeClass() {}
>>
>> MyObject* getMyObject() const
>> {
>> static MyObject* myObject;
>>
>> if(!myObject)
>> {
>> myObject = new MyObject;
>> }
>>
>> return myObject;
>> }
>> };
>
> That's another method.
> But I do want myObject be member data so other functions
> may check "myObject == NULL" when initialization is not
> required.
struct SomeClass
{
SomeClass() {}
MyObject* getMyObject( bool initialise = false ) const
{
static MyObject* myObject = NULL;
if( !myObject && initialise )
{
myObject = new MyObject;
}
return myObject;
}
};
--
Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | Narinder <narinder.claire@gmail.com> |
|---|---|
| Date | 2011-07-12 15:41 -0700 |
| Message-ID | <b645bf93-49b6-4b2f-b51c-7c8b2767a3ad@b2g2000vbo.googlegroups.com> |
| In reply to | #7670 |
On Jul 9, 8:56 am, Qi <n...@no.com> wrote:
> On 2011-7-9 15:28, Ian Collins wrote:
>
> > You don't need all those "this->".
>
> That's my personal style. I like those "this->"
> because it makes members more obvious, if not considering
> ADL. I used that style in all my C++, Java, Action Script
> code.
>
> Hope we stop here because that topic is quite subjective
> and off topic. :-)
Your style of using "this->" is definitely a good style. It's a good
habit to form. Consider the following code:
-------------------------------
#include<iostream>
using namespace std;
template<class T>
void foo(T)
{
cout << "I am global foo\n";
}
template<class U>
struct base
{
template<class T>
static void foo(T)
{
cout << "I am static foo\n";
}
void foo(U t)
{
cout << "I am in base \n";
}
};
template<class T>
struct derived :public base<T>
{
void g()
{
foo(3.0);
}
void f()
{
this->foo(3.0);
}
};
int main()
{
derived<double> d;
d.f();
d.g();
}
------------------------------
Sorry about this minor digression off-topic, but I thought it was
informative to share an actual illustrative example.
[toc] | [prev] | [next] | [standalone]
| From | SG <s.gesemann@gmail.com> |
|---|---|
| Date | 2011-07-09 01:25 -0700 |
| Message-ID | <5f166443-c96b-4931-8364-8ca307f15a29@x16g2000yqg.googlegroups.com> |
| In reply to | #7665 |
On 9 Jul., 08:19, Qi wrote:
> It's not rare to lazy initialize member field in getter functions
> which are const function.
That sounds like a job for the mutable keyword. If the const function
does not alter the observable state it's still "logical constness".
Some private mutable data member does not hurt in this case.
> class SomeClass {
> public:
> MyObject * getMyObject() const {
> if(! this->myObject) {
> this->myObject = create the object;
> }
>
> return this->myObject;
> }
>
> private:
> MyObject * myObject;
>
> };
>
> To be able to modify myObject in the getter function, we can
> either,
> 1, Use mutable on myObject.
> mutable MyObject * myObject;
Yes. Do that.
> or
> 2, Use const_cast to cast away constness from "this".
> const_cast<SomeClass *>(this)->myObject = create the object;
Bad idea. This will lead to undefined behaviour in a case like this:
const SomeClass x;
x.getMyObject(); // BOOM! U.B.
> Cons:
> A, "mutable" makes myObject to be changable to all const
> functions. This is the problem. It should not be able to be
> modified by any const functions except the lazy initialization
> (the getter).
It is not modified in terms of observable state. mutable allows you to
implement caching and things like that without altering the "logical
state" of the object. This is the purpose of mutable.
SG
[toc] | [prev] | [next] | [standalone]
| From | Werner Erasmus <werasm@gmail.com> |
|---|---|
| Date | 2011-07-10 22:25 +0200 |
| Message-ID | <U8GdnQkwR-88l4fTnZ2dnUVZ8qSdnZ2d@saix.net> |
| In reply to | #7672 |
SG wrote:
>
> Yes. Do that.
Yes (I agree), but take this little example:
class SomeClass
{
public:
const int* getMyInt() const
{
if(!myInt)
{
myInt = new int;
}
return myInt;
}
private:
int const * mutable myInt;
};
I know it fails to compile, and I imagine this is because
of 7.1.1:10, but in my opinion this should compile
because 7.1.1:10 should apply to the constness of the
int, whereas mutable applies to the mutability of the
pointer. Why does the above not compile whilst the code
below does? To me it boils down to the same thing. Your
thoughts appreciated.
int main()
{
const int* n = new int;
n = new int;
const int* const m = new int;
m = new int;
}
Kind regards,
Werner
[toc] | [prev] | [next] | [standalone]
| From | Qi <no@no.no> |
|---|---|
| Date | 2011-07-11 09:54 +0800 |
| Message-ID | <ivdl4t$fcf$1@speranza.aioe.org> |
| In reply to | #7707 |
On 2011-7-11 4:25, Werner Erasmus wrote:
> class SomeClass
> {
> public:
> const int* getMyInt() const
> {
> if(!myInt)
> {
> myInt = new int;
> }
> return myInt;
> }
>
> private:
> int const * mutable myInt;
> };
mutable int const * myInt;
Works
--
WQ
[toc] | [prev] | [next] | [standalone]
| From | Werner Erasmus <werasm@gmail.com> |
|---|---|
| Date | 2011-07-11 09:08 +0200 |
| Message-ID | <v9KdndHSr9cePIfTnZ2dnUVZ8gydnZ2d@saix.net> |
| In reply to | #7712 |
Qi wrote: > mutable int const * myInt; > > Works Thank you. Yes, my mistake. "mutable" therefore does not describe the type, but rather what operations can be performed on the type during the execution of a const member function. "const" OTOH is part of the type expression. When I expressed it as... T const* mutable t_name; //Note, compiler error. ... I confused this. Apologies. Kind regards, Werner
[toc] | [prev] | [next] | [standalone]
| From | Paavo Helde <myfirstname@osa.pri.ee> |
|---|---|
| Date | 2011-07-09 03:31 -0500 |
| Message-ID | <Xns9F1D752A09F62myfirstnameosapriee@216.196.109.131> |
| In reply to | #7665 |
Qi <no@no.com> wrote in news:iv8s22$2sp$1@speranza.aioe.org:
> It's not rare to lazy initialize member field in getter functions which
> are const function.
>
> class SomeClass {
> public:
> MyObject * getMyObject() const {
> if(! this->myObject) {
> this->myObject = create the object;
> }
>
> return this->myObject;
> }
>
> private:
> MyObject * myObject;
> };
>
> To be able to modify myObject in the getter function, we can
> either,
> 1, Use mutable on myObject.
> mutable MyObject * myObject;
> or
> 2, Use const_cast to cast away constness from "this".
> const_cast<SomeClass *>(this)->myObject = create the object;
If some SomeClass object is itself defined as const, then const_cast is
illegal. The compiler might put the object in read-only-memory or apply
optimisations assuming the content never changes, for example.
A mutable field would be fully legal OTOH. So I would go with 'mutable'
as this eliminates a potential misusage case and also clearly documents
the intent IMO.
my 2 cents
Paavo
[toc] | [prev] | [next] | [standalone]
| From | "Balog Pal" <pasa@lib.hu> |
|---|---|
| Date | 2011-07-09 10:47 +0200 |
| Message-ID | <iv94jl$31go$1@news.ett.com.ua> |
| In reply to | #7665 |
"Qi" <no@no.com> > It's not rare to lazy initialize member field in getter functions which > are const function. Changing the state of an object from a const function is generally NOT FAIR. We use mutable members to have elements that are not considered as part of the state. Like memoize cache. That can be recreated from real state. Your case is not clear where it belongs. If you have a special "empty" state, the getter discovers, it can use it to answer the query, and there is no need to alter anything. If you do alter the state, it is better to be honest about it. And not do it with either cast or mutable. For really non-state members, prefer mutable, and make special documentation/warning on that. In multithreaded world peope normally map logical constness to physical one, and may be hit by race conditions. Also, modifying an object that was originally created const is undefined behavior. Doing const_cast inside class may still be fair game in circumstances you are sure you had a non-const instance, and only gained and excess const somehow -- or you're forcing some overloads.
[toc] | [prev] | [next] | [standalone]
| From | Qi <no@no.com> |
|---|---|
| Date | 2011-07-09 16:54 +0800 |
| Message-ID | <iv954c$l4c$1@speranza.aioe.org> |
| In reply to | #7665 |
On 2011-7-9 14:19, Qi wrote: > It's not rare to lazy initialize member field in getter functions which > are const function. Hi all, Thanks you all so much for pointing out the Undefined Behavior to modify a const object. I didn't know that before. So I will definitely keep away from const_cast<>(this) and go mutable way. For anyone has interesting in learning UB on modifying const object, here is the quote from the standard 03, 7.1.5.1 p4, Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior. -- WQ
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c++
csiph-web