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

Discussion in 'C++' started by Qi, Jul 9, 2011.

  1. Qi

    Qi Guest

    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
     
    Qi, Jul 9, 2011
    #1
    1. Advertising

  2. Qi

    Narinder Guest

    Re: mutable vs const_cast, which is better to modify field from const function?

    On Jul 9, 7:19 am, 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 = 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
     
    Narinder, Jul 9, 2011
    #2
    1. Advertising

  3. Qi

    Ian Collins Guest

    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
     
    Ian Collins, Jul 9, 2011
    #3
  4. Qi

    Qi Guest

    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
     
    Qi, Jul 9, 2011
    #4
  5. Qi

    Qi Guest

    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
     
    Qi, Jul 9, 2011
    #5
  6. Qi

    Ian Collins Guest

    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
     
    Ian Collins, Jul 9, 2011
    #6
  7. Qi

    SG Guest

    Re: mutable vs const_cast, which is better to modify field from const function?

    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
     
    SG, Jul 9, 2011
    #7
  8. Qi

    Narinder Guest

    Re: mutable vs const_cast, which is better to modify field from const function?

    On Jul 9, 8:50 am, Qi <> 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;

    };
    ------------------------------------------
     
    Narinder, Jul 9, 2011
    #8
  9. Qi

    Balog Pal Guest

    Re: mutable vs const_cast, which is better to modify field from const function?

    "Qi" <>

    > 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.
     
    Balog Pal, Jul 9, 2011
    #9
  10. Qi

    Qi Guest

    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
     
    Qi, Jul 9, 2011
    #10
  11. Qi

    Qi Guest

    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
     
    Qi, Jul 11, 2011
    #11
  12. Qi

    Narinder Guest

    Re: mutable vs const_cast, which is better to modify field from const function?

    On Jul 9, 8:56 am, Qi <> 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.
     
    Narinder, Jul 12, 2011
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. CoolPint
    Replies:
    20
    Views:
    1,792
    Old Wolf
    Jul 26, 2004
  2. christopher diggins

    How bad is making a field mutable?

    christopher diggins, Jun 3, 2005, in forum: C++
    Replies:
    6
    Views:
    459
    christopher diggins
    Jun 3, 2005
  3. Immortal Nephi
    Replies:
    2
    Views:
    570
    Eric Pruneau
    Jul 1, 2008
  4. Sound
    Replies:
    2
    Views:
    449
    Randy Webb
    Sep 28, 2006
  5. jr
    Replies:
    3
    Views:
    424
Loading...

Share This Page