你用const能做到什么程度?你只是在必要的时候才把函数变成const,还是从头到尾到处都用它?例如,想象一个简单的变异子,它接受一个布尔参数:

void SetValue(const bool b) { my_val_ = b; }

这个const真的有用吗?就我个人而言,我选择广泛地使用它,包括参数,但在这种情况下,我想知道它是否值得?

我还惊讶地发现,你可以在函数声明中的形参中省略const,但可以在函数定义中包含它,例如:

. h文件

void func(int n, long l);

. cpp文件

void func(const int n, const long l)

这有什么原因吗?这对我来说有点不寻常。


当前回答

将值参数标记为“const”绝对是一件主观的事情。

然而,我实际上更喜欢将值形参标记为const,就像您的示例中一样。

void func(const int n, const long l) { /* ... */ }

对我来说,这个值清楚地表明函数的参数值永远不会被函数改变。它们在开始和结束时的值是一样的。对我来说,这是保持函数式编程风格的一部分。

对于一个简短的函数,在那里使用'const'可以说是浪费时间/空间,因为通常很明显函数不会修改实参。

然而,对于较大的函数,它是一种实现文档的形式,由编译器强制执行。

我可以肯定,如果我用'n'和'l'进行一些计算,我可以重构/移动计算,而不用担心得到不同的结果,因为我错过了一个地方,其中一个或两个都改变了。

因为它是一个实现细节,所以不需要在头文件中声明值形参const,就像不需要声明与实现使用的同名的函数形参一样。

其他回答

我倾向于尽可能使用const。(或其他适合目标语言的关键字。)我这样做纯粹是因为它允许编译器做额外的优化,否则它无法做。因为我不知道这些优化可能是什么,我总是这样做,即使它看起来很傻。

据我所知,编译器很可能看到一个const值形参,然后说:“嘿,这个函数无论如何都没有修改它,所以我可以通过引用传递并节省一些时钟周期。”我不认为它会做这样的事情,因为它改变了函数的签名,但它说明了这一点。也许它会做一些不同的堆栈操作之类的…重点是,我不知道,但我知道试图比编译器更聪明只会让我感到羞耻。

c++有一些额外的包袱,有常量正确性的思想,所以它变得更加重要。

1. 根据我的评估,最佳答案是:

根据我的评估,@Adisak的答案是最好的答案。请注意,这个答案在某种程度上是最好的,因为除了使用合理和深思熟虑的逻辑之外,它还使用了最完善的真实代码示例。

2. 我自己的话(同意最好的答案):

For pass-by-value there is no benefit to adding const. All it does is: limit the implementer to have to make a copy every time they want to change an input param in the source code (which change would have no side effects anyway since what's passed in is already a copy since it's pass-by-value). And frequently, changing an input param which is passed by value is used to implement the function, so adding const everywhere can hinder this. and adding const unnecessarily clutters the code with consts everywhere, drawing attention away from the consts that are truly necessary to have safe code. When dealing with pointers or references, however, const is critically important when needed, and must be used, as it prevents undesired side effects with persistent changes outside the function, and therefore every single pointer or reference must use const when the param is an input only, not an output. Using const only on parameters passed by reference or pointer has the additional benefit of making it really obvious which parameters are pointers or references. It's one more thing to stick out and say "Watch out! Any param with const next to it is a reference or pointer!". What I've described above has frequently been the consensus achieved in professional software organizations I have worked in, and has been considered best practice. Sometimes even, the rule has been strict: "don't ever use const on parameters which are passed by value, but always use it on parameters passed by reference or pointer if they are inputs only."

3.谷歌的话(同意我和最好的答案):

(摘自“谷歌c++风格指南”)

对于通过value传递的函数形参,const对调用者没有影响,因此不建议在函数声明中使用。参见tow #109。

对局部变量使用const既不鼓励也不鼓励。

来源:谷歌c++风格指南的“const的使用”部分:https://google.github.io/styleguide/cppguide.html#Use_of_const。这是一个非常有价值的部分,所以请阅读整个部分。

请注意,“tow# 109”代表“本周小贴士#109:函数声明中有意义的const”,这也是一个有用的阅读。它提供了更多的信息,对要做的事情的规定性更少,并且在谷歌c++样式指南关于上面引用的const规则之前出现,但由于它提供的清晰性,上面引用的const规则被添加到谷歌c++样式指南中。

Also note that even though I'm quoting the Google C++ Style Guide here in defense of my position, it does NOT mean I always follow the guide or always recommend following the guide. Some of the things they recommend are just plain weird, such as their kDaysInAWeek-style naming convention for "Constant Names". However, it is still nonetheless useful and relevant to point out when one of the world's most successful and influential technical and software companies uses the same justification as I and others like @Adisak do to back up our viewpoints on this matter.

4. Clang的linter, Clang -tidy,有一些选项:

答:同样值得注意的是,Clang的linter, Clang -tidy,有一个选项,可读性-avoid-const-params-in-decls,描述在这里,以支持在代码库中强制不使用const的值传递函数参数:

检查函数声明的形参是否为顶级const。

声明中的Const值不会影响函数的签名,因此它们不应该放在那里。

例子:

Void f(const字符串);//错误:const是顶级的。 Void f(const string&);//好:const不是顶级的。

为了完整和清晰,我自己再举两个例子:

void f(char * const c_string);   // Bad: const is top level. [This makes the _pointer itself_, NOT what it points to, const]
void f(const char * c_string);   // Good: const is not top level. [This makes what is being _pointed to_ const]

B.它还有这个选项:readable -const-return-type - https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html

5. 我的务实的方法是如何在这个问题上给出一个风格指南:

我只需复制粘贴到我的风格指南中:

[复制/ START纸浆]

Always use const on function parameters passed by reference or pointer when their contents (what they point to) are intended NOT to be changed. This way, it becomes obvious when a variable passed by reference or pointer IS expected to be changed, because it will lack const. In this use case const prevents accidental side effects outside the function. It is not recommended to use const on function parameters passed by value, because const has no effect on the caller: even if the variable is changed in the function there will be no side effects outside the function. See the following resources for additional justification and insight: "Google C++ Style Guide" "Use of const" section "Tip of the Week #109: Meaningful const in Function Declarations" Adisak's Stack Overflow answer on "Use of 'const' for function parameters" "Never use top-level const [ie: const on parameters passed by value] on function parameters in declarations that are not definitions (and be careful not to copy/paste a meaningless const). It is meaningless and ignored by the compiler, it is visual noise, and it could mislead readers" (https://abseil.io/tips/109, emphasis added). The only const qualifiers that have an effect on compilation are those placed in the function definition, NOT those in a forward declaration of the function, such as in a function (method) declaration in a header file. Never use top-level const [ie: const on variables passed by value] on values returned by a function. Using const on pointers or references returned by a function is up to the implementer, as it is sometimes useful. TODO: enforce some of the above with the following clang-tidy options: https://clang.llvm.org/extra/clang-tidy/checks/readability-avoid-const-params-in-decls.html https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html

下面是一些演示上述const规则的代码示例:

参数示例: (有些是从这里借来的)

void f(const std::string);   // Bad: const is top level.
void f(const std::string&);  // Good: const is not top level.

void f(char * const c_string);   // Bad: const is top level. [This makes the _pointer itself_, NOT what it points to, const]
void f(const char * c_string);   // Good: const is not top level. [This makes what is being _pointed to_ const]

示例: (有些是从这里借来的)

// BAD--do not do this:
const int foo();
const Clazz foo();
Clazz *const foo();

// OK--up to the implementer:
const int* foo();
const int& foo();
const Clazz* foo();

复制/ PASTE黑的外星人探索铝

关键词:const在函数形参中的应用;编码标准;C和c++编码标准;编码规则;最佳实践;代码标准;Const返回值

你的例子中所有的const都没有目的。c++默认情况下是值传递的,因此该函数获得这些整型和布尔型的副本。即使函数修改了它们,调用者的副本也不会受到影响。

所以我会避免额外的const,因为

他们redudant 他们弄得乱七八糟 文本 他们阻止我 更改传入的值 它可能有用或有效的情况。

确实没有理由将值形参设为“const”,因为函数只能修改变量的副本。

使用“const”的原因是如果你通过引用传递更大的东西(例如有很多成员的结构体),在这种情况下,它确保函数不能修改它;或者更确切地说,如果您试图以常规方式修改它,编译器将报错。它可以防止它被意外修改。

将值参数标记为“const”绝对是一件主观的事情。

然而,我实际上更喜欢将值形参标记为const,就像您的示例中一样。

void func(const int n, const long l) { /* ... */ }

对我来说,这个值清楚地表明函数的参数值永远不会被函数改变。它们在开始和结束时的值是一样的。对我来说,这是保持函数式编程风格的一部分。

对于一个简短的函数,在那里使用'const'可以说是浪费时间/空间,因为通常很明显函数不会修改实参。

然而,对于较大的函数,它是一种实现文档的形式,由编译器强制执行。

我可以肯定,如果我用'n'和'l'进行一些计算,我可以重构/移动计算,而不用担心得到不同的结果,因为我错过了一个地方,其中一个或两个都改变了。

因为它是一个实现细节,所以不需要在头文件中声明值形参const,就像不需要声明与实现使用的同名的函数形参一样。