const version of a function w/o copy/paste

Discussion in 'C++' started by Gernot Frisch, Jul 22, 2010.

  1. Hi,

    // how can I
    const int* GetPInt()const
    {
    return (const int*)the_non_const_function_using_the_same_name();
    }

    thank you.
    -Gernot
     
    Gernot Frisch, Jul 22, 2010
    #1
    1. Advertising

  2. On 7/22/2010 8:33 AM, Gernot Frisch wrote:
    > // how can I
    > const int* GetPInt()const
    > {
    > return (const int*)the_non_const_function_using_the_same_name();
    > }


    You could do

    return const_cast<YourType*>(this)->GetPInt();

    but beware of UB. The use of const_cast is only defined *if* you know
    for sure that the object is non-const. If you don't, it's UB.

    Now, let me ask you, why do you have two versions of the same function?
    If they do exactly same thing (and do not change the state of the
    object), then drop the non-const one. If they *don't* do the exactly
    same thing, then you have no business calling a non-const member from a
    const member.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 22, 2010
    #2
    1. Advertising


  3. > Now, let me ask you, why do you have two versions of the same function?


    I access members through a pointer. Now, the object can be a const pointer, thus I only get a const pointer to the child and
    vice versa:

    class child;
    class parent
    {
    child* GetChild() {return &m_child;}
    const child* GetChild()const {return &m_child;} // for when parent prt is const
    };

    thanks for the const cast hint.
     
    Gernot Frisch, Jul 22, 2010
    #3
  4. On 7/22/2010 9:26 AM, Gernot Frisch wrote:
    >
    >
    >> Now, let me ask you, why do you have two versions of the same function?

    >
    > I access members through a pointer.


    That's rather odd. Shouldn't it be a reference?

    > Now, the object can be a const
    > pointer, thus I only get a const pointer to the child and vice versa:
    >
    > class child;
    > class parent
    > {
    > child* GetChild() {return &m_child;}
    > const child* GetChild()const {return &m_child;} // for when parent prt
    > is const
    > };
    >
    > thanks for the const cast hint.


    It is *better* to have two accessors like you've shown here, than go
    through the complexity of "forwarding" from the const accessor to the
    non-const one. Cleaner.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 22, 2010
    #4
  5. On 7/22/2010 9:19 AM, Stuart Golodetz wrote:
    > Gernot Frisch wrote:
    >>
    >> Hi,
    >>
    >> // how can I
    >> const int* GetPInt()const
    >> {
    >> return (const int*)the_non_const_function_using_the_same_name();
    >> }
    >>
    >> thank you.
    >> -Gernot

    >
    > You should do it the other way round - call the const version from the
    > non-const one.[..]


    +1

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 22, 2010
    #5
  6. Gernot Frisch

    James Kanze Guest

    On Jul 22, 2:12 pm, Victor Bazarov <> wrote:
    > On 7/22/2010 8:33 AM, Gernot Frisch wrote:


    > > // how can I
    > > const int* GetPInt()const
    > > {
    > > return (const int*)the_non_const_function_using_the_same_name();
    > > }


    > You could do


    > return const_cast<YourType*>(this)->GetPInt();


    > but beware of UB. The use of const_cast is only defined *if*
    > you know for sure that the object is non-const. If you don't,
    > it's UB.


    No. It's only UB if you actually attempt to modify a const
    object.

    Still, I'd prefer the inverse, calling the const function from
    within the non-const one, then casting away const on the results
    (since you know that you're not really const there).

    > Now, let me ask you, why do you have two versions of the same
    > function?


    > If they do exactly same thing (and do not change the state of
    > the object), then drop the non-const one.


    The two functions have different return types. Both in fact do
    exactly the same thing, but the return value of one allows
    client code to modify the object; the return type of the other
    doesn't.

    This is a standard idiom for container classes (where GetPInt is
    named operator[], and returns a reference rather than a pointer).

    --
    James
     
    James Kanze, Jul 22, 2010
    #6
  7. Gernot Frisch

    Bo Persson Guest

    Stuart Golodetz wrote:
    > Victor Bazarov wrote:
    >> On 7/22/2010 8:33 AM, Gernot Frisch wrote:
    >>> // how can I
    >>> const int* GetPInt()const
    >>> {
    >>> return (const int*)the_non_const_function_using_the_same_name();
    >>> }

    >>
    >> You could do
    >>
    >> return const_cast<YourType*>(this)->GetPInt();
    >>
    >> but beware of UB. The use of const_cast is only defined *if* you
    >> know for sure that the object is non-const. If you don't, it's UB.
    >>
    >> Now, let me ask you, why do you have two versions of the same
    >> function? If they do exactly same thing (and do not change the
    >> state of the object), then drop the non-const one. If they
    >> *don't* do the exactly same thing, then you have no business
    >> calling a non-const member from a const member.
    >>
    >> V

    >
    > Presumably the non-const one returns int*, so clients can change
    > something in the object through that, but only if the object itself
    > is non-const. If the object's const, you want to return a const
    > int* to the same thing. Whether or not the class should be exposing
    > its internal data like this at all depends on the context I guess.
    >
    > It's evidently "evil" to call a non-const member from a const one,
    > but I was under the impression that there's nothing particularly
    > evil about doing it the other way round - in fact, I thought it was
    > almost
    > idiomatic if you need to provide both a non-const and const
    > accessor? It's certainly better than duplicating the code, which is
    > the
    > alternative...


    It surely depends on what the functions do. The one returning an int*
    to class member will likely be

    int* getbuffer()
    { return &buffer; }

    const int* getbuffer() const
    { return &buffer; }


    How much duplication can you save here?


    Bo Persson
     
    Bo Persson, Jul 22, 2010
    #7
  8. On 22 Jul., 14:33, "Gernot Frisch" <> wrote:
    > Hi,
    >
    > // how can I
    > const int* GetPInt()const
    > {
    >     return (const int*)the_non_const_function_using_the_same_name();
    >
    > }


    We had a similar topic quite recently (http://groups.google.de/group/
    comp.lang.c++/browse_frm/thread/7943a399a96324bf#), and came up with
    the following class:


    // Wrapper for plain pointers that behaves as const-correct
    // accessor.
    template<class t_Class>
    class ConstCorrectAccessor
    {
    t_Class* m_InternalPointer;
    public:
    ConstCorrectAccessor (t_Class* Pointer)
    : m_InternalPointer (Pointer)
    {}


    // Accessor methods with const-correct overload.
    const t_Class* operator-> () const {return m_InternalPointer;}
    t_Class* operator ->() {return m_InternalPointer;}



    };


    class SomeClass
    {
    public:
    void foo () const {}
    void bar () {}


    };


    class AnotherClass
    {
    public:
    ConstCorrectAccessor<SomeClass> SomeObject;
    public:
    AnotherClass (SomeClass* Object)
    : SomeObject (Object)
    {}

    void foo () const
    {
    SomeObject->foo (); // OK
    SomeObject->bar (); // Error: Non-const method on SomeObject.
    }



    };


    int main ()
    {
    SomeClass a;
    const AnotherClass b (&a);
    b.SomeObject->foo (); // OK
    b.SomeObject->bar (); // Compilation error: b is const

    AnotherClass c (&a);
    c.SomeObject->foo (); // OK
    c.SomeObject->bar (); // OK: c is not const



    }


    Regards,
    Stuart
     
    Stuart Redmann, Jul 23, 2010
    #8
  9. "Stuart Golodetz" <> schrieb im Newsbeitrag
    news:...


    > Yes, unless the accessor does something non-trivial, in which case it's (arguably) better not to duplicate the code (less to
    > maintain). As an example I've managed to dig up:
    >
    > int& SliceLocation::eek:perator[](SliceOrientation ori)
    > {
    > return const_cast<int&>(const_cast<const SliceLocation*>(this)->operator[](ori));
    > }



    Excellent. That was exaclty the reason why I asked this question.
     
    Gernot Frisch, Jul 26, 2010
    #9
    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. Replies:
    11
    Views:
    1,109
  2. Javier
    Replies:
    2
    Views:
    569
    James Kanze
    Sep 4, 2007
  3. V Green
    Replies:
    0
    Views:
    863
    V Green
    Feb 5, 2008
  4. PA Bear [MS MVP]
    Replies:
    0
    Views:
    973
    PA Bear [MS MVP]
    Feb 5, 2008
  5. Replies:
    1
    Views:
    314
Loading...

Share This Page