制作一个基本(非指针)参数const是否有意义?

Sco*_*ith 14 c++ const const-correctness

我最近与另一位C++开发人员就以下用途进行了交流const:

void Foo(const int bar);
Run Code Online (Sandbox Code Playgroud)

他认为const以这种方式使用是很好的做法.

我认为它对函数的调用者没有任何作用(因为参数的副本将被传递,因此对于覆盖没有额外的安全保证).此外,这样做可以防止实现者Foo修改其参数的私有副本.因此,它既要求又要宣传实施细节.

不是世界末日,但肯定不是值得推荐的良好做法.

我很好奇别人对这个问题的看法.

编辑:

好吧,我没有意识到参数的常数没有考虑到函数的签名.因此,可以const在实现(.cpp)中标记参数,而不是在标题(.h)中标记- 并且编译器就可以了.既然如此,我想政策应该与制作局部变量const相同.

人们可以提出这样的论点:在标题和源文件中具有不同的看起来签名会使其他人感到困惑(因为它会使我感到困惑).虽然我试着用我写的任何内容来遵循最小惊讶原则,但我认为期望开发人员认为这是合法且有用的是合理的.

pae*_*bal 27

还记得if(NULL == p)模式吗?

有很多人会说"你必须写这样的代码":

if(NULL == myPointer) { /* etc. */ }
Run Code Online (Sandbox Code Playgroud)

代替

if(myPointer == NULL) { /* etc. */ }
Run Code Online (Sandbox Code Playgroud)

基本原理是第一个版本将保护编码器免于代码拼写错误,例如将"=="替换为"="(因为禁止将值赋给常量值).

以下可以被视为这种有限if(NULL == p)模式的扩展:

为什么常量参数对编码器有用

无论类型如何,"const"都是一个限定符,我向编译器说" 我不希望值发生变化,所以如果我说谎,请发送编译器错误消息 ".

例如,这种代码将显示编译器何时可以帮助我:

void bar_const(const int & param) ;
void bar_non_const(int & param) ;

void foo(const int param)
{
   const int value = getValue() ;

   if(param == 25) { /* Etc. */ } // Ok
   if(value == 25) { /* Etc. */ } // Ok

   if(param = 25) { /* Etc. */ } // COMPILE ERROR
   if(value = 25) { /* Etc. */ } // COMPILE ERROR

   bar_const(param) ;  // Ok
   bar_const(value) ;  // Ok

   bar_non_const(param) ;  // COMPILE ERROR
   bar_non_const(value) ;  // COMPILE ERROR

   // Here, I expect to continue to use "param" and "value" with
   // their original values, so having some random code or error
   // change it would be a runtime error...
}
Run Code Online (Sandbox Code Playgroud)

在那些情况下,可能由代码错误或函数调用中的一些错误发生,将由编译器捕获,这是一件好事.

为什么它对用户来说并不重要

碰巧:

void foo(const int param) ;
Run Code Online (Sandbox Code Playgroud)

和:

void foo(int param) ;
Run Code Online (Sandbox Code Playgroud)

有相同的签名.

这是一件好事,因为,如果函数实现者决定一个参数在函数内被认为是const,那么用户不应该,也不需要知道它.

这解释了为什么我的函数声明给用户省略了const:

void bar(int param, const char * p) ;
Run Code Online (Sandbox Code Playgroud)

保持声明尽可能清晰,而我的函数定义尽可能地添加它:

void bar(const int param, const char * const p)
{
   // etc.
}
Run Code Online (Sandbox Code Playgroud)

使我的代码尽可能健壮.

为什么在现实世界中,它可能会破裂

不过,我被我的模式所困扰.

在一些将保持匿名的破坏的编译器(其名称以" Sol " 开头并以" aris CC " 结尾),上面的两个签名可以被视为不同(取决于上下文),因此,运行时链接可能会失败.

由于项目也是在Unix平台上编译的(Linux和Solaris),在这些平台上,未定义的符号在执行时被解析,这在执行过程中引发了运行时错误.

所以,因为我不得不支持所说的编译器,所以我结束了使用已经开始的原型来污染我的标题.

但我仍然认为这种在函数定义中添加const的模式是一个很好的模式.

注意:Sun Microsystems甚至还用球来隐藏他们破碎的破损,并且" 无论如何都是邪恶的模式,所以你不应该使用它 "的声明.见http://docs.oracle.com/cd/E19059-01/stud.9/817-6698/Ch1.Intro.html#71468

最后一点

必须注意的是,Bjarne Stroustrup似乎反对考虑void foo(int)相同的原型void foo(const int):

不过,并非所有接受的功能都是我认为的改进.例如,void f(T)和void f(const T)的规则表示相同的函数(由于Pl兼容性原因由Tom Plum提出)[有]被投票到C++中的可疑区别"在我的尸体上".

来源:Bjarne的Stroustrup的
演进语言在和现实世界中:C++ 1991-2006,5,语言特点:1991- 1998年,P21.
http://www.stroustrup.com/hopl-almost-final.pdf

考虑到Herb Sutter提供了相反的观点,这很有趣:

准则:避免在函数声明中使用const pass-by-value参数.如果不修改参数const仍然在同一函数的定义中.

来源:Herb Sutter
Exceptional C++,Item 43:Const- Correctness,p177-178.


Jer*_*fin 7

这已经多次讨论过,大多数人最终不得不同意不同意.就个人而言,我同意这是毫无意义的,并且标准隐含地同意 - 顶级const(或volatile)限定符不构成函数签名的一部分.在我看来,想要使用这样的顶级限定符表明(强烈地)该人可能会为将界面与实现分离而口头上说,但并不真正理解这种区别.

另一个小细节:虽然它确实适用于引用以及指针...

  • +1因为我大多同意,但所有标准都说是问题中使用的顶级const是函数的实现细节,而不是接口的一部分.说标准同意,没有意义的是读得太多了. (3认同)