You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@qpid.apache.org by Alan Conway <ac...@redhat.com> on 2015/04/02 18:18:45 UTC

C++ tip: use of const [ignore at will]

I'm looking at some code that has a bunch of const mistakes in it,
thought I'd offer a quick tip. 

The placement of const in C++ is confusing. The secret is that there is
actually a simple, logical rule for const with one wildly confusing
exception, and almost everybody uses the exception. The actual C++ rule
is:

"const refers to the thing that comes _before_ it *except* if const is
the first thing in the declaration in which case it refers to the thing
_after_ it"

If you always put const *after* the thing it modifies, complex type
expressions are easy to read. Many (most?) programmers don't, I still
don't in Qpid because I don't want pile inconsistency on confusion. But
once you know the rule, you can mentally flip that first const around
and it all becomes clear. 

[Aside: The Sacred Rule of C++ is: "Never break any code written since
the dawn of C no matter how insanely complex the language becomes".
const-before works for simple expressions and was used in early C++. By
the time they realized it *doesn't* work for complex expressions, people
had written code so the Sacred Rule kicked in and now we have
const-after-except-when-its-before.]

const-before is clear enough for simple expressions:

    const int* p;  // Cannot use p to modify the int.

But what about this:

    const int* const p; // Huh? What?

Now look how easy it is to read if you stick to const-after:

    int const *p;        // int is const, cannot modify the int.
    int const *const p;  // int is const and * is const: cannot modify the int or make the pointer point elsewhere
    int *const p;        // * is const: *can* modify the int but *cannot* make the pointer point elsewhere

Here's the huh, what example again but now you can flip it:

    const int* const p; // Huh? What?
    int const * const p; // Ahhh, yes, int is const, * is const. Of course.


Some of the above examples are unrealistic though, let me explain. 

It is often useful to declare a pointer to a const value, so whoever gets the pointer can't mess with the value:

   foo const *p // the logical way
   const foo *p // the ugly way

But there is *rarely* any point in making the pointer or reference
*itself* const. In particular it is *never* useful to make a function
parameter or return type const. These const are all utterly useless:

    foo *const f(const int i1, int const i2, foo *const p)

In C++ parameters are passed by value so a function can *never* change
its parameters, const or not. It can only change things the parameters
point (or refer) to.

However declaring that the things the parameters point/refer to *is*
useful.

     foo const* f(foo const* p, foo const& r)
     const foo* f(const foo* p, const foo& r) // The ugly version

It can be useful to declare pointers const if they themselves are being
pointed at or referred to or are part of something being pointed at or
referred to, but not if they are being passed as parameters.

References work like pointers insofar as declaring the thing they refer
to as const. Unlike pointers you can't declare the reference itself to
be const:

     int const &i = ...; // Good, can't use reference to change the int
     int& const i = ...; // WRONG, reference itself can't be const.

This is because references are already immutable, you can't change what
they refer to. C++ references are like pointers in a frilly dress and
high heels - prettier but less mobile.

Cheers,
Alan.



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@qpid.apache.org
For additional commands, e-mail: dev-help@qpid.apache.org


RE: C++ tip: use of const [ignore at will]

Posted by Steve Huston <sh...@riverace.com>.
Excellent explanation - thanks, Alan!

> -----Original Message-----
> From: Alan Conway [mailto:aconway@redhat.com]
> Sent: Thursday, April 02, 2015 12:19 PM
> To: dev
> Subject: C++ tip: use of const [ignore at will]
> 
> I'm looking at some code that has a bunch of const mistakes in it, thought I'd
> offer a quick tip.
> 
> The placement of const in C++ is confusing. The secret is that there is actually
> a simple, logical rule for const with one wildly confusing exception, and
> almost everybody uses the exception. The actual C++ rule
> is:
> 
> "const refers to the thing that comes _before_ it *except* if const is the first
> thing in the declaration in which case it refers to the thing _after_ it"
> 
> If you always put const *after* the thing it modifies, complex type
> expressions are easy to read. Many (most?) programmers don't, I still don't
> in Qpid because I don't want pile inconsistency on confusion. But once you
> know the rule, you can mentally flip that first const around and it all becomes
> clear.
> 
> [Aside: The Sacred Rule of C++ is: "Never break any code written since the
> dawn of C no matter how insanely complex the language becomes".
> const-before works for simple expressions and was used in early C++. By the
> time they realized it *doesn't* work for complex expressions, people had
> written code so the Sacred Rule kicked in and now we have const-after-
> except-when-its-before.]
> 
> const-before is clear enough for simple expressions:
> 
>     const int* p;  // Cannot use p to modify the int.
> 
> But what about this:
> 
>     const int* const p; // Huh? What?
> 
> Now look how easy it is to read if you stick to const-after:
> 
>     int const *p;        // int is const, cannot modify the int.
>     int const *const p;  // int is const and * is const: cannot modify the int or
> make the pointer point elsewhere
>     int *const p;        // * is const: *can* modify the int but *cannot* make the
> pointer point elsewhere
> 
> Here's the huh, what example again but now you can flip it:
> 
>     const int* const p; // Huh? What?
>     int const * const p; // Ahhh, yes, int is const, * is const. Of course.
> 
> 
> Some of the above examples are unrealistic though, let me explain.
> 
> It is often useful to declare a pointer to a const value, so whoever gets the
> pointer can't mess with the value:
> 
>    foo const *p // the logical way
>    const foo *p // the ugly way
> 
> But there is *rarely* any point in making the pointer or reference
> *itself* const. In particular it is *never* useful to make a function parameter
> or return type const. These const are all utterly useless:
> 
>     foo *const f(const int i1, int const i2, foo *const p)
> 
> In C++ parameters are passed by value so a function can *never* change its
> parameters, const or not. It can only change things the parameters point (or
> refer) to.
> 
> However declaring that the things the parameters point/refer to *is* useful.
> 
>      foo const* f(foo const* p, foo const& r)
>      const foo* f(const foo* p, const foo& r) // The ugly version
> 
> It can be useful to declare pointers const if they themselves are being
> pointed at or referred to or are part of something being pointed at or
> referred to, but not if they are being passed as parameters.
> 
> References work like pointers insofar as declaring the thing they refer to as
> const. Unlike pointers you can't declare the reference itself to be const:
> 
>      int const &i = ...; // Good, can't use reference to change the int
>      int& const i = ...; // WRONG, reference itself can't be const.
> 
> This is because references are already immutable, you can't change what
> they refer to. C++ references are like pointers in a frilly dress and high heels -
> prettier but less mobile.
> 
> Cheers,
> Alan.
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@qpid.apache.org For additional
> commands, e-mail: dev-help@qpid.apache.org