Topic: Simplifying cost-correctness


Author: "Earl Purple" <earlpurple@gmail.com>
Date: Tue, 25 Apr 2006 20:57:02 CST
Raw View
Ivan Kolev wrote:

> class Monkey
> {
>     Finger& getFinger( int i );
>
>     const Finger& getFinger( int i ) const;
> }
>
> Duplication or a const_cast seems inevitable to me. And I also can't
> see the dangers of the const_cast which Martin Vejn   r mentioned.

template < typename M, typename F >
F & getFinger( M& m )
{
   // complex code
}

Finger& Monkey::getFinger( int i )
{
   return getFinger< Monkey, Finger >( i);
}

const Finger & Monkey::getFinger( int i ) const
{
   return getFinger< const Monkey, const Finger >( i );
}

Of course the getFinger template is a free-function and not a friend
plus you want to hide this implementation detail completely in the
header so it probably gets out of hand just to avoid a 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.comeaucomputing.com/csc/faq.html                      ]





Author: Sylvain Pion <Sylvain.Pion@sophia.inria.fr>
Date: Mon, 10 Apr 2006 11:38:11 CST
Raw View
When one writes const-correct classes, usually a lot of code
has to be duplicated between the const and the non-const version
of the member functions.

I was wondering if there is some ongoing to work on attempting
to enhance the language to simplify this task (e.g. some way of
factorizing the code between the two versions in a compact
manner) ?

--
Sylvain

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Tom s" <NULL@NULL.NULL>
Date: Mon, 10 Apr 2006 12:17:07 CST
Raw View
Sylvain Pion posted:

> When one writes const-correct classes, usually a lot of code
> has to be duplicated between the const and the non-const version
> of the member functions.
>
> I was wondering if there is some ongoing to work on attempting
> to enhance the language to simplify this task (e.g. some way of
> factorizing the code between the two versions in a compact
> manner) ?
>

Do any of you do something akin to the following:

class Monkey
{
    const Monkey& Climb() const
    {
        //Very complicated function containing
        //a thousand lines of code

        return *this;
    }

    Monkey& Climb()
    {
        const Monkey& untouchable = *this;

        return const_cast<Monkey&>( untouchable.Climb() );
    }
};


Seems like a very legitimate use of "const_cast" to me.


-Tom   s

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Mon, 10 Apr 2006 17:40:10 GMT
Raw View
Sylvain Pion <Sylvain.Pion@sophia.inria.fr> writes:

> When one writes const-correct classes, usually a lot of code
> has to be duplicated between the const and the non-const version
> of the member functions.
>
> I was wondering if there is some ongoing to work on attempting
> to enhance the language to simplify this task (e.g. some way of
> factorizing the code between the two versions in a compact
> manner) ?

Not that I know of.  I'd like to see cv qualification as a template
parameter:

        template <class T, cvqual CV>
        struct foo
        {
             int CV x;  // for example
        };

That could make these things much easier to handle cleanly.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kevin.hall@motioneng.com
Date: Mon, 10 Apr 2006 16:04:39 CST
Raw View
Yes, I do this exact same thing.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: spam@spamguard.com ("Gene Bushuyev")
Date: Tue, 11 Apr 2006 15:41:22 GMT
Raw View
"Sylvain Pion" <Sylvain.Pion@sophia.inria.fr> wrote in message
news:e1e1fd$pkf$1@news-sop.inria.fr...
> When one writes const-correct classes, usually a lot of code
> has to be duplicated between the const and the non-const version
> of the member functions.
>
> I was wondering if there is some ongoing to work on attempting
> to enhance the language to simplify this task (e.g. some way of
> factorizing the code between the two versions in a compact
> manner) ?


It was discussed before on std.c++. You can find discussion and some solutions
here:
http://groups.google.com/group/comp.std.c++/tree/browse_frm/thread/c7f237927b1eb150/81d70ed62abce301?rnum=1&_done=%2Fgroup%2Fcomp.std.c%2B%2B%2Fbrowse_frm%2Fthread%2Fc7f237927b1eb150%2F81d70ed62abce301%3Ftvc%3D1%26#doc_36b01fac9172235a

--
Gene Bushuyev (www.gbresearch.com)
----------------------------------------------------------------
There is no greatness where there is no simplicity, goodness and truth. ~ Leo
Tolstoy

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Bronek Kozicki <brok@rubikon.pl>
Date: Thu, 13 Apr 2006 10:35:37 CST
Raw View
David Abrahams wrote:
>> I was wondering if there is some ongoing to work on attempting
>> to enhance the language to simplify this task (e.g. some way of
>> factorizing the code between the two versions in a compact
>> manner) ?
>
> Not that I know of.  I'd like to see cv qualification as a template
> parameter:


and I'd like to see const constructor that can be used only to create const
objects. That would allow 1. more flexibility in defining class interface; 2.
performance optimizations when creating const objects.

struct A
{
   A(); // 1
   A() const; // 2
};

class B
{
   B(); // 3
public:
   B() const; // 4
};

int main()
{
   A a1; // 1 called
   const A a2; // 2 called
   B b1; // error, constructor 3 not accessible
   const B b2; // 4 called
}

.. but there was not such proposal, thus there's no chance having something
like this in C++0x . Oh, and while we are at this; with "rvalue-this" we could
extend semantics to have separate constructor for creation of temporary
variables and for creation of named variables (direct-initialization)


B.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: avakar@volny.cz (=?ISO-8859-1?Q?Martin_Vejn=E1r?=)
Date: Fri, 14 Apr 2006 07:33:13 GMT
Raw View
Tom=E1s wrote:
> Sylvain Pion posted:
>> When one writes const-correct classes, usually a lot of code
>> has to be duplicated between the const and the non-const version
>> of the member functions.
>>
>> I was wondering if there is some ongoing to work on attempting
>> to enhance the language to simplify this task (e.g. some way of
>> factorizing the code between the two versions in a compact
>> manner) ?
>>
>=20
> Do any of you do something akin to the following:
>=20
> class Monkey
> {
>     const Monkey& Climb() const
>     {
>         //Very complicated function containing
>         //a thousand lines of code
>=20
>         return *this;
>     }
>=20
>     Monkey& Climb()
>     {
>         const Monkey& untouchable =3D *this;
>=20
>         return const_cast<Monkey&>( untouchable.Climb() );
>     }
> };
>=20
>=20
> Seems like a very legitimate use of "const_cast" to me.

Why don't you do it this way? It seems cleaner to me...

class Monkey
{
     void Climb2() const
     {
         //Very complicated function containing
         //a thousand lines of code
     }

     Monkey & Climb()
     {
         Climb2();
         return *this;
     }

     const Monkey & Climb() const
     {
         Climb2();
         return *this;
     }
};

OP was talking about duplicating "a lot of code" in const-correct=20
classes. I don't think that two lines are that many. Surely not enough=20
to advocate a use of a cast.

Although the code you (Tom=E1s) posted is correct _now_, after several=20
modifications by different people, the cast may not be valid anymore. By=20
using that explicit cast, you deliberately and unnecessarily give up=20
type checking and expose yourself to unexpected behaviors.

--=20
Martin

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Ivan Kolev" <ikolev@gmail.com>
Date: Fri, 14 Apr 2006 02:33:26 CST
Raw View
kevin.hall@motioneng.com wrote:
> Yes, I do this exact same thing.

I found that the opposite is usually more convenient:

class Monkey
{
    const Monkey& Climb() const
    {
        return const_cast<Monkey&>(*this).Climb();
    }

    Monkey& Climb()
    {
        //Very complicated function containing
        //a thousand lines of code

        return *this;
    }

};

And I think this idiom is obligatory even for simple functions (and
even for the most performance-sensitive one-liners, which should be
inline anyway and an additional one-line call would surely be inlined
too), to avoid the possible modification of just one of the two methods
in the future.

> Seems like a very legitimate use of "const_cast" to me.

Indeed, I hope so, too.

Regards,
Ivan

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: NULL@NULL.NULL ("Tom s")
Date: Fri, 14 Apr 2006 15:51:38 GMT
Raw View
Martin Vejn=E1r posted:

> class Monkey
> {
>      void Climb2() const
>      {
>          //Very complicated function containing
>          //a thousand lines of code
>      }
>=20
>      Monkey & Climb()
>      {
>          Climb2();
>          return *this;
>      }
>=20
>      const Monkey & Climb() const
>      {
>          Climb2();
>          return *this;
>      }
> };


Good solution.

I simply hadn't thought of that at the time of posting. Once again, this=20
proves that there's many solutions to any particular problem, and that so=
me=20
solutions are better than others. Best thing is just to sit down and thin=
k,=20
think, think...


-Tom=E1s

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: brok@rubikon.pl (Bronek Kozicki)
Date: Fri, 14 Apr 2006 16:05:08 GMT
Raw View
Ivan Kolev wrote:
> I found that the opposite is usually more convenient:
>
>     const Monkey& Climb() const
>     {
>         return const_cast<Monkey&>(*this).Climb();
>     }

this is wrong. See what happens here:

const Monkey doda;
// . . .
doda.Climb();

here you effectively cast-away constness of doda object, which is UB. You
could notice funny symptoms if doda had static lifetime - such const objects
may live in immutable regions of memory and any member variable modification
in body of non-const Climb would result in memory access violation.


B.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Ivan Kolev" <ikolev@gmail.com>
Date: 16 Apr 2006 04:50:02 GMT
Raw View
"Tom   s" wrote:
> Martin Vejn   r posted:
>
> > class Monkey
> > {
> >      void Climb2() const
> >      {
> >          //Very complicated function containing
> >          //a thousand lines of code
> >      }
> >
> >      Monkey & Climb()
> >      {
> >          Climb2();
> >          return *this;
> >      }
> >
> >      const Monkey & Climb() const
> >      {
> >          Climb2();
> >          return *this;
> >      }
> > };
>
>
> Good solution.

However, I don't see this working in the case when the two methods must
return a part of the object, which is not trivially retrieved:

class Monkey
{
    Finger& getFinger( int i );

    const Finger& getFinger( int i ) const;
}

Duplication or a const_cast seems inevitable to me. And I also can't
see the dangers of the const_cast which Martin Vejn   r mentioned.

But I agree with Bronek Kozicki that it's better to write the common
implementation inside the const method - not exactly because of the
reasons he gave (if the two methods are actually exactly the same
method with two faces, then that method *cannot* modify any member
variable), but because by writing the implementation inside the const
method the compiler will point out if you modify a member variable by
mistake.

Regards,
Ivan


---
[ 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.comeaucomputing.com/csc/faq.html                      ]