在类型ID可接受的C ++中是“const”吗?

时间:2009-06-12 17:50:24

标签: c++ coding-style

我的同事在他受到启发的问题上是2比0(12),所以我想我会给他一个机会赶上来。

我们最近的分歧是关于将“const”放在声明上的样式问题。

他认为它应该在类型前面,或者在指针之后。原因在于,这是其他人通常所做的事情,其他风格可能会让人感到困惑。因此,指向常量int的指针和指向int的常量指针将分别为:

const int *i;
      int * const i;

然而,无论如何,我很困惑。我需要一致且易于理解的规则,而我能理解“const”的唯一方法就是之后修改它。有一个例外允许它在最终类型之前,但这是一个例外,所以如果我不使用它,对我来说会更容易。

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

int const * i;
int * const i;

作为一个额外的好处,以这种方式做事使得更深层次的间接更容易理解。例如,指向int的常量指针的指针显然是:

int * const * i;

我的论点是,如果有人只是按照自己的方式学习,他们就可以轻而易举地找出上述内容。

这里的最终问题是他认为将int放在int之后是如此难以言喻的丑陋,并且对可读性有害,以至于它应该在样式指南中被禁止。当然,我认为如果指南应该建议按照我的方式进行,但无论哪种方式,我们都不应该禁止一种方法。

修改 我得到了很多好的答案,但没有一个真正直接解决我的最后一段(“最终问题”)。很多人都争论一致性,但在这种情况下这是非常可取的,禁止以其他方式做到这一点是个好主意,而不仅仅是阻止它?

15 个答案:

答案 0 :(得分:48)

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

那就是说,我认为到目前为止更常见的是

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

答案 1 :(得分:13)

有一类示例将const放在类型的右侧也有助于避免混淆。

如果在typedef中有指针类型,则无法将的常量更改为类型:

typedef int * PINT;
const PINT pi;

'pi'仍然具有'int * const'类型,无论你在哪里写'const',这都是一样的。

答案 2 :(得分:11)

我希望B. Stroustrup关于Style& amp;技术会给你一个明确的答案。

Bjarne Stroustrup's C++ Style and Technique FAQ


我个人更喜欢:

int const* pi;
int* const pi;

因为const标识了旨在成为const的左标记。

当你像这样使用smth时,你肯定保持相同的一致性:

int const* const pi;

而不是写不一致:

const int* const pi;

如果你有一个指针指针等等会发生什么:

int const* const* const pi;

而不是:

const int* const* const pi;

答案 3 :(得分:8)

我正在参加Bjarne Stroustrup发表演讲的会议,他使用了像const int * i这样的东西;有人问他为什么这种风格和他回应(释义):“当事情不变时,人们喜欢先看到const。”

答案 4 :(得分:7)

人们通常使用const int* blah,因为它可以很好地使用英语。我不会低估它的用处。

我发现int* const blah变化非常罕见,因此向后制作更常见的定义通常并不常见。总的来说,我并不喜欢在一般情况下甚至略微模糊代码的任何东西,尽管它可能在特殊情况下提供一些名义上的好处。

另请参阅“if(1 == a)”。有些人真的很喜欢编写不懂英文的代码。我不是那些人之一。

但是,真的,const背后的规则很简单。向左看,然后向右看。如此简单,我不认为它在风格指南中值得关注。

答案 5 :(得分:6)

如果只有变量和指针可能是const,那么它可能并不重要。但请考虑:

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

除了尾随它所引用的功能之外,其他任何地方都无法写入const

样式指南越短,开发人员就越有可能遵循它。并且可能的最短规则以及 only 规则将为您提供一致性

const关键字总是跟踪无论它指的是什么。

所以,我在这里为你的同事说0:3。

关于你的“终极问题”:为了风格指南,无关紧要指南是否“劝阻”或“禁止”它所反对的事情。这是一个社会问题,一个政策。风格指南本身应尽可能简洁明快。长篇导游只会被所有人忽略(管理层除了要注意责怪的人),所以只需写下“做”或“不做”,并说明你在其他地方违反指南的行为(例如在公司政策中)如何进行同行评审)。

答案 6 :(得分:5)

虽然const intint const之间没有任何有意义的差异(我已经看过两种使用的样式),但const int *int * const之间存在差异。

在第一个中,你有一个指向const int的指针。您可以更改指针,但不能更改它指向的值。在第二个中,你有一个指向int的const指针。你不能改变指针(希望它根据你的喜好初始化),但是你可以改变指向int的值。

正确的比较是const int *int const *,它们都是指向const int的指针。

请记住,*并不一定像您所希望的那样有效。声明int x, y;将按预期工作,但int* x, y;声明一个指向int的指针,一个int。

答案 7 :(得分:4)

训练自己从右到左阅读C ++类型声明后,在类型声明后添加“const”会更有意义。

我打算以0比3的方式将你的牛盯住:)

答案 8 :(得分: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 :-)

答案 9 :(得分:3)

  

这里的最终问题是他认为将int放在int之后是如此难以言喻的丑陋,并且对可读性有害,以至于它应该在样式指南中被禁止

真的?

告诉我一个程序员,当他看到时陷入困境:

int foo() {
}

vs

int foo()
{
}

...我会告诉你一个程序员,他不会对细节给予足够的重视。

没有值得他的盐的专业程序员会遇到表面上的肤浅差异的问题。

编辑:确实,const int *和int * const并不意味着完全相同,但这不是重点。 OP的同事提出的观点是,风格的差异使得代码难以理解。保持。这是我不同意的主张。

答案 10 :(得分:3)

让我把我的2¢放进讨论中。

在现代C ++中,我建议坚持使用int const代替const int来强调constconstexpr之间的区别。这将有助于程序员记住const int不能总是被认为是编译时常量,因为:

  • 编译器可以(将?)为它分配内存,
  • 这个内存甚至可能没有写保护(堆栈段),
  • 此常数无法提供all the duties constexpr can

答案 11 :(得分:2)

规则很好。更简单的规则更好。 Const走到了const的右侧。

采取此声明:

INT 主要     (int const argc     ,char const * const * const argv     ) ...

答案 12 :(得分:2)

我想使用以下表单声明"manifest constants"。在这种情况下,值本身是一个常量,所以我把“const”放在第一位(same as Bjarne)以强调constness应该在编译时显示,并且可以由编译器用于特定的优化。 / p>

const int i = 123;

为了声明不会用于修改值的引用,我使用以下形式强调标识符是“常量引用”这一事实。引用的值可以是也可以不是常量。 [相关讨论:如果函数参数不是指针或引用,你甚至会使用“const”吗? Use of 'const' for function parameters]

void fn( int const & i );

对于指针,我使用与引用相同的形式,原因基本相同(尽管术语“常量指针”似乎比“常量引用”更加模糊)。

void fn( int const * i );

另外,正如另一张海报所指出的,当你有多个间接层时,这个表格保持一致。

void fn( int const * const * i );

在我使用C ++的经历中,最后一个场景,你声明一个常量指针是非常罕见的。无论如何,你在这里没有任何选择。 [这个案例表明,最一致的方法是在类型之后加上“const”这个词 - 因为事实上,这个特定声明的必需。 ]

void fn( int * const i );

...除非你使用typedef。

typedef int * IntPtr;

void fn1( const IntPtr i );
void fn2( IntPtr const i );

最后要注意的是:除非您在低级别域中工作,否则大多数C ++代码应永远不会声明指针。因此,本讨论的这一方面可能与C更相关。

答案 13 :(得分:2)

我同意你们两个。你应该把const放在类型之后。我也发现它看起来是一种必须被摧毁的憎恶。但是我最近涉足const value parameters的奇迹让我理解为什么把第二个有意义。

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

只是看着我脖子上的毛发竖立着。我相信这会让我的同事感到困惑。

编辑:我只是想在课堂上使用它:

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

bar在功能上等同于Bar&,但它在堆上并且可以删除。对于每个Foo的生命周期,将有一个与之关联的Bar。

答案 14 :(得分:1)

在现代C ++ 11中,您还可以使用模板typedef来增加复杂声明的清晰度:

template<typename T>
using Const = const T;

template<typename T>
using Ptr = T*;

您在问题中提到的三个声明:

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

然后写成:

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