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

2019-01-17 15:23发布

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?

15条回答
仙女界的扛把子
2楼-- · 2019-01-17 16:07

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

查看更多
贪生不怕死
3楼-- · 2019-01-17 16:10

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.

查看更多
【Aperson】
4楼-- · 2019-01-17 16:11

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.

查看更多
Bombasti
5楼-- · 2019-01-17 16:12

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

查看更多
smile是对你的礼貌
6楼-- · 2019-01-17 16:13

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

查看更多
混吃等死
7楼-- · 2019-01-17 16: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.

查看更多
登录 后发表回答