Tutorial :In C++ is “const” after type ID acceptable?



Question:

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?


Solution:1

The most important thing is consistency. If there aren't any coding guidelines for this, then pick one and stick with it. But, if your team already has a de facto standard, don't change it!

That said, I think by far the more common is

const int* i;  int* const j;  

because most people write

const int n;  

instead of

int const n;  

A side note -- an easy way to read pointer constness is to read the declaration starting at the right.

const int* i; // pointer to an int that is const  int* const j; // constant pointer to a (non-const) int  int const* aLessPopularWay; // pointer to a const int  


Solution:2

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:

typedef int * PINT;  const PINT pi;  

'pi' still has the type 'int * const', and this is the same no matter where you write the 'const'.


Solution:3

I hope this explanation from B. Stroustrup's FAQ on Style & Techniques will give you a definite answer.

Bjarne Stroustrup's C++ Style and Technique FAQ


I personaly prefer:

int const* pi;  int* const pi;  

Because const identifies the left token which is intended to be const.

And you definitely keep the same consistency when using smth like that:

int const* const pi;  

Instead of writing inconsistently:

const int* const pi;  

And what happens if you have a pointer to pointer and so on:

int const* const* const pi;  

Instead of:

const int* const* const pi;  

Regards,

Ovanes


Solution:4

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".


Solution:5

People typically use const int* blah because it reads well as English. I wouldn't underestimate the usefulness of that.

I find that the int* const blah variation is rare enough that it's not typically useful to make the more common definition backwards. I am, in general, not a fan of anything that even slightly obscures code in the general case, though it might provide some nominal benefit in the exceptional case.

See also "if (1 == a)". Some people really enjoy writing code that doesn't read as English. I am not one of those people.

Really, though, the rules behind const are simple. Look to the left, then to the right. So simple that I wouldn't think it's worth much attention in a style guide.


Solution:6

If it were only variables and pointers to them that could be const or not, it would probably not matter that much. But consider:

class MyClass  {      public:          int foo() const;  };  

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).


Solution:7

While there is no meaningful difference between const int and int const (and I've seen both styles in use), there is a difference between const int * and int * 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 * and int const *, which both are pointers to a const int.

Remember that the * doesn't necessarily work as you might like. The declaration int x, y; will work as you expect, but int* x, y; declares one pointer to int, and one int.


Solution:8

Putting "const" after the type declaration makes a whole lot more sense once you train yourself to read your C++ type declarations from right to left.

I'm going to peg your cow-orker at 0-for-3 :)


Solution:9

Personally I (and it is a personal preeference) I finding reading type declarations from right to left the easiest. Especially when you start throwing references into the mix.

std::string const&  name = plop; // reference to const string.    const std::string&  flame =plop; // reference to string const;                                   // That works better if you are German I suppose :-)  


Solution:10

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

Really?

Show me a programmer who gets bogged down when he sees:

int foo() {  }  

vs

int foo()  {  }  

...and I'll show you a programmer who doesn't pay close enough attention to detail.

No professional programmer worth his salt will have a problem with superficial differences in style.

EDIT: It is true that const int* and int* const don't mean exactly the same thing, but that wasn't the point. The point made by OP's coworker was that differences in style make code difficult to understand & maintain. It is this claim I disagree with.


Solution:11

Let me put my 2¢ into the discussion.

In modern C++ I'd recommend to stick to int const instead of const int to highlight the difference between const and constexpr. It would help programmer to remember that const int cannot be always thought as compile-time constant, because:

  • compiler may (will?) allocate memory for it,
  • this memory may even be not write-protected (stack segment),
  • such a constant cannot serve all the duties constexpr can.


Solution:12

Rules are good to follow. Simpler rules are better. Const goes to the right of what's const.

Take this declaration:

int main ( int const argc , char const * const * const argv ) ...


Solution:13

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.

int *  int const *  int * const  int const * const  

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:

class Foo {      Bar* const bar;      Foo(const Foo&) = delete; // would cause too many headaches  public:      Foo() : bar(new Bar) {}      ~Foo() { delete bar; }  };  

bar in this example is functionally equivalent to Bar& 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.


Solution:14

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.

const int i = 123;  

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]

void fn( int const & i );  

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").

void fn( int const * i );  

Also, as another poster noted, this form remains consistent when you have multiple levels of indirection.

void fn( int const * const * i );  

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.]

void fn( int * const i );  

...unless you use a typedef.

typedef int * IntPtr;    void fn1( const IntPtr i );  void fn2( IntPtr const i );  

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.


Solution:15

In modern C++11, you could also use template typedefs to add clarity to complicated declarations:

template<typename T>  using Const = const T;    template<typename T>  using Ptr = T*;  

The three declarations you mentioned in your question:

int const * a;  int * const b;  int * const * c;  

would then be written as:

Ptr<Const<int>> a;  Const<Ptr<int>> b;  Ptr<Const<Ptr<int>>> c;  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »