const int *p和int const *p之间有什么区别?在类型后使用const是否可行?

30

我的同事在启发他人提问方面0-2落后(1, 2),所以我想给他一个机会追赶。

我们最近的争论是关于将"const"放在声明的哪个位置的风格问题。

他认为应该将其放在类型之前或指针之后。理由是这是其他人通常采用的方式,其他风格容易引起混淆。因此,指向常量int的指针和指向int的常量指针分别应为:

const int *i;
      int * const i;

然而,我仍然感到困惑。我需要一些一致且易于理解的规则,而我能够理解 "const" 的唯一方法是它放在所修改的内容之后。const有一个例外情况,允许它放在最终类型的前面,但那只是个例外,如果我不使用它会更容易理解。

因此,指向常量 int 的指针和一个指向 int 的常量指针分别为:

int const * i;
int * const i;

采用这种方式的另一个好处是更容易理解更深层次的间接引用。例如,指向常量指针int的指针会清晰明了地表示为:

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;

我的观点是,如果有人按照自己的方式学习,他们很容易弄清楚上述内容的意思。

最终问题在于,他认为在 int 之后添加 const 太难看了,对可读性也非常有害,应该在样式指南中禁止这种写法。当然,我认为如果有必要,指南应该建议按照我的方式进行,但无论如何,我们都不应该 禁止 这种做法。

编辑: 我得到了很多好答案,但没有一个真正针对我最后一段话(“最终问题”)进行回答。很多人主张保持一致性,但是这种情况下保持一致性是否值得我们把另一种方法给禁止呢?我们只需建议避免使用即可。


1
另一个重要的点是,什么更重要?它是int类型还是它是常量? - rlbond
@rlbond:这是一个好问题……好到我不确定我能回答它。 - T.E.D.
@T.E.D. 关于您的编辑:风格指南的意义是什么?它是开发人员可以随意忽略的建议,还是他们应该遵循的规则?如果您只是反对特定的风格,那么这不就意味着它只是一个建议吗? - atk
@atk:在这种情况下,我相信应该是后者。 - T.E.D.
@T.E.D. 为什么你只在 C++ 的背景下提出这个问题?我在这里看不到与 C 有任何区别。 - RobertS supports Monica Cellio
@T.E.D. 此外,这是一个好问题,但没有一个适当的标题。我甚至在搜索关键字中找不到那个问题;我只是通过你在答案 https://dev59.com/0HM_5IYBdhLWcg3w-4dg#1143418 中的链接到 const int *,const int * const和int const *之间有什么区别? 无意中来到这里。所以我选择了一个更好的标题,让人们可以更有效地找到这个问题。 - RobertS supports Monica Cellio
15个回答

55

最重要的是一致性。如果没有编码指南,那么选择一个并坚持下去。但是,如果您的团队已经有了事实上的标准,请不要更改它!

话虽如此,我认为迄今为止最常见的是

const int * i;
int * const j;

由于大多数人写代码的习惯

const int n;

代替

int const n;

顺便提一下——读指针的const属性的简单方法是从右侧开始阅读声明。

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

4
你觉得有更多的人是用另一种方式做吗?就我个人而言,我经常看到 const type*。 - rlbond
15
虽然不是非常科学的结果,但是通过Google代码搜索,在使用lang:c++语言的情况下,“int const *”有41个结果,“const int *”有824个结果。 - Richard Corden
1
一致性并不是那么重要,更重要的是灵活性和多样性。 - Brent Bradburn
2
@finnw:我总是惊叹于为什么人们坚持*必须紧邻任何东西。写上 int * i;,不仅两个“派别”都不会因为你支持另一个观点而责怪你,而且任何人忽略*的机会实际上比其他两种选择要少。 - DevSolar
@DevSolar 我同意,但我已经删除了我的原始评论,因为SO上的评论标记使其混乱不堪。 - finnw
显示剩余7条评论

13

有一类例子,在类型右侧使用 const 也有助于避免混淆。

如果您在 typedef 中有一个指针类型,则无法更改 to 类型的常量性:

typedef int * PINT;
const PINT pi;

pi仍然具有类型int * const,而且无论你在哪里写const,它都是相同的。


5
我认为这并不太难理解。你的例子是一个常量指针 (const int*),因为 typedef 的作用类似于分组 -- 类似于 (int*) const。相反,一个指向常量的指针是一个 (const int)* 或者 (int const)*。 - rlbond
5
如果您能看到PINT并说:“这是一个typedef,因此const不适用于指向的成员,因为我知道标准关于typedef的规定。”,那么这就不会令人困惑。如果 PINT 是宏定义呢?那么规则就不同了,CV限定符将适用于该类型。合理地讲,您的代码应该尽可能清晰明了,没有歧义。 - Richard Corden
超前的我......东方常数!http://slashslash.info/2018/02/a-foolish-consistency/ https://www.reddit.com/r/cpp/comments/80k8hc/a_blog_rant_on_east_const/ - Richard Corden

11

我希望这篇B. Stroustrup的风格和技巧FAQ中的解释能给你一个明确的答案。

Bjarne Stroustrup的C++风格和技巧FAQ


个人而言,我更喜欢:

int const* pi;
int* const pi;

因为const标识左侧的标记是想要被定义成常量的。

当使用类似的语法时,你一定要保持相同的一致性:

int const* const pi;

不要写得不一致:

const int* const pi;

如果您有一个指向指针的指针,会发生什么:

int const* const* const pi;

改为:

const int* const* const pi;

8

我曾参加过一次由Bjarne Stroustrup举行的会议,他在演示中用到了类似于const int* i的东西。有人问他为什么要使用这种风格,他回答道(引用):

"当某物是常数时,人们喜欢先看到const。"


8
很遗憾,他没有将这个原则应用于“const”的语法一般情况,否则我们就不会有这样的讨论了。 - T.E.D.
Stroustrup 可能与 "const" 的语法关系不大,因为 C++ 只是从 C 中继承了它。据我记得,它并不是 K&R C 的一部分,但是在 1990 年的标准中被引入了。 - David Thornley
3
C++的起源可以追溯到1983年,前身是在70年代后期出现的“带类的C语言”。C++最早拥有const关键字,它是在C90标准中被引入到C语言中的。 - Pieter
据我所知,C++是在C考虑之后得到了const关键字,最终放弃了"readonly"。 - Max Lybbert
6
Bjarne声称他发明了const关键字:http://www.research.att.com/~bs/bs%5Ffaq2.html#constplacement。这篇文章还提到,Bjarne最初考虑使用“readonly”。 - Brent Bradburn

7
人们通常使用const int* blah,因为它读起来像英语。我不会低估这的有用性。
我发现int* const blah的变化很少见,所以将更常见的定义倒过来通常没有什么用处。总的来说,在一般情况下,我不喜欢任何稍微模糊代码的东西,尽管在特殊情况下可能会提供一些名义上的好处。
另请参见“if (1 == a)”。“有些人真的很喜欢编写看起来不像英语的代码。我不是其中的一个人。”
但是,实际上,const背后的规则很简单。向左看,然后向右看。太简单了,以至于我认为在样式指南中不值得太多关注。

2
这个问题实际上在争论中出现过。作为一个老的Ada编码人员,我觉得有点好笑。如果代码用英语阅读困难对你来说是个问题,那么你根本不应该使用C语法语言。它并不是为了英语般的可读性而设计的,试图将其强加在上面只会让你发疯。 - T.E.D.
3
作为一名老旧的 C++ 程序员,我认为如果在常见情况下使用 const 左侧的小不一致对你来说是一个问题,那么你就根本没有使用 C 语法的业务。 C 语言并不是为了一致性而设计的,试图强制实施一些东西只会让你发疯。说真的,你和你的朋友已经浪费了更多时间争论这个问题,比起选择你们中任何一个人提出的标准化方案所能节省的时间都要多。解雇那些不能理解两种语法的人,然后就此结束。 - Dan Olson
@T.E.D:我认为那是一个伪命题的论点。仅仅因为“完美”的可读性不可能实现,我们仍然可以努力让它更易读一些。特别是,当有机会时,为什么不让变量声明看起来与其口头表述相同呢? - jalf
“...命名为blah”。我想我可以接受这个。请注意,您必须使用第一人称现在完成时来表达它。比“Blah是一个常量整数”更尴尬。但公平就是公平。把它放在答案中,我会撤回我的踩(SO不允许我改变投票,除非答案发生了变化)。 - T.E.D.
嘿,根据维基百科的说法,你使用的实际上是“现在进行时”,而不是我的“一般现在时”。我想你可以通过将其更改为“声明一个...”来使其成为命令语气。 - T.E.D.
没关系。在我的看法中,“常量整型指针”比“整型常量指针”更易读,但是“常量”可以充当形容词和名词,而在两种情况下,“整型”都被错误地用作形容词(我认为)。这是一个偏好问题。如果我必须在可读性和一致性之间做出选择,在这种情况下我会选择可读性,因为我认为由于可读性造成的明晰度损失在这种情况下更糟糕。 - Dan Olson

6

如果只有变量和指向它们的指针可以是const或不是const,那么这可能并不重要。但请考虑以下情况:

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

没有其他地方可以编写const,只能在它所引用的函数后面。

风格指南越短,开发人员遵循的可能性就越大。而最短的规则,也是唯一能给你一致性的规则是:

const关键字总是跟随它所引用的内容。

所以,我认为你的同事得分是0:3。

关于你的“最终问题”:为了风格指南,无论指南“反对”还是“禁止”它所提出的内容都无所谓。那是一个社会问题,一项政策。风格指南本身应该尽可能简洁明了。长风格指南只会被每个人忽略(除了管理层在寻找责任人),所以只需编写“做”或“不做”,并说明你如何处理违反指南的情况(例如,在公司政策中说明如何进行同行评审)。


但是foo方法本身不是const。 - Wolf
@Wolf:是的,它是一个常量成员函数 - DevSolar
我知道,那是它的名称,但成员函数的const性质与数据的不同。 - Wolf
@Wolf:但是重点仍然是:您可以随时将“const”说明符放置在其引用的右侧,但只有在一些特殊情况下才能将其放置在左侧 - DevSolar
当然,const <type> <whatever> 这种模式在数据声明中似乎非常普遍。我一直使用它,但现在我真的考虑重新思考这个问题。 - Wolf

5
虽然const intint const之间没有实质性的区别(我见过这两种风格的使用),但是const int *int * const之间有区别。
在第一种情况下,您有一个指向常量整数的指针。您可以更改指针,但不能更改它指向的值。在第二种情况下,您有一个指向整数的常量指针。您无法更改指针(希望它已经按您的喜好初始化了),但可以更改所指向的整数的值。
适当的比较应该是const int *int const *,它们都是指向常量整数的指针。
请记住,*可能不像您希望的那样工作。声明int x, y;将按预期工作,但int* x, y;声明一个指向整数的指针和一个整数。

4

在类型声明后面加上"const",一旦你训练自己从右往左读取C++类型声明,这就更有意义了。

我要把你的同事评为0分:)


但如果你从左到右阅读,这是正常情况,例如 const int N = 26 可以被理解为 常量整数 N 的值为 26 - Wolf
@Wolf:而 int const N = 26 可以读作 整数常量 N 的值为 26 - DevSolar
@DevSolar,是的,完全正确(正如我发现的那样,对我的英语水平感到抱歉)。再次感谢您的澄清 :) - Wolf

3

个人而言(这是个人偏好),我发现从右到左阅读类型声明最容易。特别是当你开始混合引用时。

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

当然,你也可以说const std::string&,从左到右读起来很好。 - rlbond
1
我的同事恰好懂德语,所以这可能是问题的一部分。 :-) - T.E.D.
+1 德语使用者应该将 'int const' 理解为 整数常量,这样可以避免痛苦。 - Wolf

3

这里的最终问题在于他认为在int后面添加const太难看,对可读性有害,应该在样式指南中禁止

真的吗?

给我展示一个程序员看到以下代码就会陷入困境:

int foo() {
}

vs

int foo()
{
}

如果你给我一个程序员,他不够注意细节,我会向你展示一个不太合格的程序员。

任何一位专业的程序员都不会对表面上的风格差异感到困扰。

编辑:确实,const int*和int* const并不完全意味着相同的事情,但这不是重点。OP的同事所指出的是,风格上的差异使得代码难以理解和维护。而这正是我不同意的观点。


3
给我展示一个认为这两个东西意思相同的程序员,我会给你展示一个没有足够关注细节的程序员。 - David Thornley
虽然它们的意思不同,但这不是争论的重点。争论的焦点在于风格上的差异“对可读性如此有害”,以至于应该被禁止。如果你不喜欢const int与int const的争论,没关系。我们可以把谈话扩大到花括号上。我的观点是,没有好的程序员会因为风格差异而无法理解代码。所以不要为小事烦恼。 - John Dibling
2
实际上,差异的根源在于“const int *”与“int const *”。 - T.E.D.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接