My co-worker is 0 for 2 on questions he has inspired (1, 2), so I thought I'd give him a chance to catch up.
Our latest disagreement is over the style issue of where to put "const" on declarations.
He is of the opinion that it should go either in front of the type, or after the pointer. The reasoning is that this is what is typically done by everyone else, and other styles are liable to be confusing. Thus a pointer to a constant int, and a constant pointer to int would be respectively:
const int *i;
int * const i;
However, I'm confused anyway. I need rules that are consistent and easy to understand, and the only way I can make sense of "const" is that it goes after the thing it is modifying. There's an exception that allows it to go in front of the final type, but that's an exception, so it's easier on me if I don't use it.
Thus a pointer to a constant int, and a constant pointer to int would be respectively:
int const * i;
int * const i;
As an added benefit, doing things this way makes deeper levels of indirection easier to understand. For example, a pointer to a constant pointer to int would clearly be:
int * const * i;
My contention is that if someone just learns it his way, they'll have little trouble figuring out what the above works out to.
The ultimate issue here is that he thinks that putting const after int is so unspeakably ugly, and so harmful to readability that it should be banned in the style guide. Of course, I think if anything the guide should suggest doing it my way, but either way we shouldn't be banning one approach.
Edit: I've gotten a lot of good answers, but none really directly address my last paragraph ("The ultimate issue"). A lot of people argue for consistency, but is that so desirable in this case that it is a good idea to ban the other way of doing it, rather that just discouraging it?
If it were only variables and pointers to them that could be
const
or not, it would probably not matter that much. But consider:No way that
const
could be written anywhere else but trailing the function it refers to.The shorter a style guide, the more likely developers will follow it. And the shortest rule possible, and the only rule that will give you consistency, is:
The
const
keyword always trails whatever it is referring to.So, I'd say 0:3 for your coworker here.
Regarding your "ultimate issue": For the sake of the style guide, it does not matter whether the guide "discourages" or "bans" the things it speaks out against. That is a social issue, a policy. The style guide itself should be as crisp and short as possible. Long style guides just get ignored by everybody (except management on the lookout for someone to blame), so just write "do" or "don't", and state what you do with violations of the guide elsewhere (e.g. in the company policy of how peer reviews are being done).
I like to to use the following form for declaring "manifest constants". In this case, the value itself is a constant so I put the "const" first (same as Bjarne) to emphasize that the constness should be manifest at compile-time, and usable as such for specific optimizations by the compiler.
For declaring references which will not be used to modify the value, I use the following form which emphasizes the fact that the identifier is a "constant reference". The referenced value may or may not be a constant. [Related discussion: Would you even be using "const" for function parameters if they were not pointers or references? Use of 'const' for function parameters]
For pointers, I use the same form that I use for references, for essentially the same reason (although the term "constant pointer" seems a little more ambiguous than "constant reference").
Also, as another poster noted, this form remains consistent when you have multiple levels of indirection.
The final scenario, where you are declaring a pointer which is constant is pretty rare in my experience with C++. In any case, you don't really have any choices here. [This case demonstrates that the most consistent approach would be to put the word "const" after the type -- since that is, in fact, required for this particular declaration.]
...unless you use a typedef.
One final note: Unless you are working in a low-level domain, most C++ code should never declare a pointer. Therefore, that aspect of this discussion is probably more relevant to C.
While there is no meaningful difference between
const int
andint const
(and I've seen both styles in use), there is a difference betweenconst int *
andint * const
.In the first, you have a pointer to a const int. You can change the pointer, but you can't change the value it points to. In the second, you have a const pointer to int. You can't change the pointer (hope it's initialized to your liking), but you can change the value of the pointed-to int.
The proper comparison is with
const int *
andint const *
, which both are pointers to a const int.Remember that the
*
doesn't necessarily work as you might like. The declarationint x, y;
will work as you expect, butint* x, y;
declares one pointer to int, and one int.I was at a conference where Bjarne Stroustrup was giving a presentation, and he used something like const int* i; Someone asked him why this style and he responded (paraphrasing): "people like to see const first when something is constant".
There's a class of examples where putting the const on the right of the type also helps avoid confusion.
If you have a pointer type in a typedef, then it is not possible to change the constness of the to type:
'pi' still has the type 'int * const', and this is the same no matter where you write the 'const'.
I agree with both of you. You should put the const after the type. I also find looking at it an abomination that must be destroyed. But my recent foray into the wonders of const value parameters has made me understand why putting the const second makes sense.
Just looking at that has the hairs on my neck standing. I'm sure it would confuse my co-workers.
EDIT: I was just wondering about using this in classes:
bar
in this example is functionally equivalent toBar&
but it is on the heap and can be deleted. For the lifetime of each Foo, there will be a single Bar associated with it.