Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > mutable vs const_cast, which is better to modify field from constfunction?

Reply
Thread Tools

mutable vs const_cast, which is better to modify field from constfunction?

 
 
Qi
Guest
Posts: n/a
 
      07-09-2011
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
 
Reply With Quote
 
 
 
 
Narinder
Guest
Posts: n/a
 
      07-09-2011
On Jul 9, 7:19*am, Qi <(E-Mail Removed)> 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 = createthe 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






 
Reply With Quote
 
 
 
 
Ian Collins
Guest
Posts: n/a
 
      07-09-2011
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
 
Reply With Quote
 
Qi
Guest
Posts: n/a
 
      07-09-2011
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
 
Reply With Quote
 
Qi
Guest
Posts: n/a
 
      07-09-2011
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
 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      07-09-2011
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
 
Reply With Quote
 
SG
Guest
Posts: n/a
 
      07-09-2011
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 = createthe 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
 
Reply With Quote
 
Narinder
Guest
Posts: n/a
 
      07-09-2011
On Jul 9, 8:50*am, Qi <(E-Mail Removed)> 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;

};
------------------------------------------



 
Reply With Quote
 
Balog Pal
Guest
Posts: n/a
 
      07-09-2011
"Qi" <(E-Mail Removed)>

> 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.

 
Reply With Quote
 
Qi
Guest
Posts: n/a
 
      07-09-2011
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.
results in undefined behavior.


--
WQ
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
javascript validation for a not required field, field is onlyrequired if another field has a value jr Javascript 3 07-08-2010 10:33 AM
AspectJ modify property field content or add and/or change methodbody in a runtime instance Jimmy Java 11 08-09-2009 07:03 PM
1.Enter space bar for field names and save the field.The field shoud not get saved and an alert should be there as"Space bars are not allowed" Sound Javascript 2 09-28-2006 02:43 PM
How bad is making a field mutable? christopher diggins C++ 6 06-03-2005 04:17 PM
Build a Better Blair (like Build a Better Bush, only better) Kenny Computer Support 0 05-06-2005 04:50 AM



Advertisments