我的同事在他受到启发的问题上是2比0(1,2),所以我想我会给他一个机会赶上来。
我们最近的分歧是关于将“const”放在声明上的样式问题。
他认为它应该在类型前面,或者在指针之后。原因在于,这是其他人通常所做的事情,其他风格可能会让人感到困惑。因此,指向常量int的指针和指向int的常量指针将分别为:
const int *i;
int * const i;
然而,无论如何,我很困惑。我需要一致且易于理解的规则,而我能理解“const”的唯一方法就是在之后修改它。有一个例外允许它在最终类型之前,但这是一个例外,所以如果我不使用它,对我来说会更容易。
因此,指向常量int的指针和指向int的常量指针将分别为:
int const * i;
int * const i;
作为一个额外的好处,以这种方式做事使得更深层次的间接更容易理解。例如,指向int的常量指针的指针显然是:
int * const * i;
我的论点是,如果有人只是按照自己的方式学习,他们就可以轻而易举地找出上述内容。
这里的最终问题是他认为将int放在int之后是如此难以言喻的丑陋,并且对可读性有害,以至于它应该在样式指南中被禁止。当然,我认为如果指南应该建议按照我的方式进行,但无论哪种方式,我们都不应该禁止一种方法。
修改 我得到了很多好的答案,但没有一个真正直接解决我的最后一段(“最终问题”)。很多人都争论一致性,但在这种情况下这是非常可取的,禁止以其他方式做到这一点是个好主意,而不仅仅是阻止它?
答案 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 int
和int 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
来强调const
和constexpr
之间的区别。这将有助于程序员记住const int
不能总是被认为是编译时常量,因为:
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;