在函数参数上使用 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) { /* ... */ }
这是有原因的吗? 对我来说这似乎有点不寻常。
For example, imagine a simple mutator that takes a single boolean parameter:
void SetValue(const bool b) { my_val_ = b; }
Does that const
actually have any impact? Personally I opt to use it extensively, including parameters, but in this case I wonder if it makes any difference.
I was also surprised to learn that you can omit const
from parameters in a function declaration but can include it in the function definition, e.g.:
.h file
void func(int n, long l);
.cpp file
void func(const int n, const long l) { /* ... */ }
Is there a reason for this? It seems a little unusual to me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
作为需要使用具有 50 多个公开函数的 C++ 程序以及偶尔使用 const 限定符的 .h 文件的 VB.NET 程序员,很难知道何时使用 ByRef 或 ByVal 访问变量。
当然,程序会通过在出错的行上生成异常错误来告诉您,但是您需要猜测 2-10 个参数中哪一个是错误的。
因此,现在我面临着一项令人厌恶的任务,即试图说服开发人员他们应该以允许轻松创建所有 VB.NET 函数定义的自动化方法的方式真正定义变量(在 .h 文件中)。 然后他们会沾沾自喜地说:“阅读……文档。”
我编写了一个 awk 脚本来解析 .h 文件,并创建所有 Declare Function 命令,但没有指示哪些变量是 R/O 还是 R/W,它只完成了一半的工作。
编辑:
在另一位用户的鼓励下,我添加了以下内容;
这是一个(IMO)格式不良的 .h 条目的示例;
我的脚本生成的 VB;
请注意第一个参数上缺少“const”。 如果没有它,程序(或其他开发人员)就不会知道第一个参数应该传递“ByVal”。 通过添加“const”,它使 .h 文件自我记录,以便使用其他语言的开发人员可以轻松编写工作代码。
Being a VB.NET programmer that needs to use a C++ program with 50+ exposed functions, and a .h file that sporadically uses the const qualifier, it is difficult to know when to access a variable using ByRef or ByVal.
Of course the program tells you by generating an exception error on the line where you made the mistake, but then you need to guess which of the 2-10 parameters is wrong.
So now I have the distasteful task of trying to convince a developer that they should really define their variables (in the .h file) in a manner that allows an automated method of creating all of the VB.NET function definitions easily. They will then smugly say, "read the ... documentation."
I have written an awk script that parses a .h file, and creates all of the Declare Function commands, but without an indicator as to which variables are R/O vs R/W, it only does half the job.
EDIT:
At the encouragement of another user I am adding the following;
Here is an example of a (IMO) poorly formed .h entry;
The resultant VB from my script;
Note the missing "const" on the first parameter. Without it, a program (or another developer) has no Idea the 1st parameter should be passed "ByVal." By adding the "const" it makes the .h file self documenting so that developers using other languages can easily write working code.
仅当参数通过引用(即引用或指针)传递时,Const 参数才有用。 当编译器看到 const 参数时,它会确保参数中使用的变量不会在函数体内被修改。 为什么有人想要将按值参数设置为常量? :-)
Const parameter is useful only when the parameter is passed by reference i.e., either reference or pointer. When compiler sees a const parameter, it make sure that the variable used in the parameter is not modified within the body of the function. Why would anyone want to make a by-value parameter as constant? :-)
使用 const 需要记住的一点是,从一开始就将事物设为 const 比稍后尝试将它们放入要容易得多。
当您希望某些内容保持不变时,请使用 const - 它是一个附加提示,描述您的函数的作用和期望。 我见过很多 C API 可以处理其中的一些,尤其是那些接受 C 字符串的 API!
与标题相比,我更倾向于省略 cpp 文件中的 const 关键字,但由于我倾向于剪切+粘贴它们,因此它们会保留在两个位置。 我不知道为什么编译器允许这样做,我猜这是编译器的事情。 最佳实践肯定是将 const 关键字放在两个文件中。
the thing to remember with const is that it is much easier to make things const from the start, than it is to try and put them in later.
Use const when you want something to be unchanged - its an added hint that describes what your function does and what to expect. I've seen many an C API that could do with some of them, especially ones that accept c-strings!
I'd be more inclined to omit the const keyword in the cpp file than the header, but as I tend to cut+paste them, they'd be kept in both places. I have no idea why the compiler allows that, I guess its a compiler thing. Best practice is definitely to put your const keyword in both files.
由于参数是按值传递的,因此从调用函数的角度来看,是否指定 const 没有任何区别。将按值传递参数声明为 const 基本上没有任何意义。
As parameters are being passed by value,it doesnt make any difference if you specify const or not from the calling function's perspective.It basically does not make any sense to declare pass by value parameters as const.
你的例子中的所有常量都没有目的。 C++ 默认情况下是按值传递的,因此该函数获取这些整数和布尔值的副本。 即使函数确实修改了它们,调用者的副本也不会受到影响。
所以我会避免额外的const,因为
文本
改变传入的值
它可能有用或有效的情况。
All the consts in your examples have no purpose. C++ is pass-by-value by default, so the function gets copies of those ints and booleans. Even if the function does modify them, the caller's copy is not affected.
So I'd avoid extra consts because
the text
changing the passed in value in
cases where it might be useful or efficient.
我知道这个问题“有点”过时,但当我遇到这个问题时,其他人将来也可能会这样做......我仍然怀疑这个可怜的家伙会在这里列出来阅读我的评论:)
在我看来我们仍然太局限于C风格的思维方式。 在 OOP 范式中,我们使用的是对象,而不是类型。 Const 对象在概念上可能与非 const 对象不同,特别是在逻辑 const 的意义上(与按位 const 相对)。 因此,即使函数参数的 const 正确性(也许)在 POD 中过于谨慎,但在对象中却并非如此。 如果一个函数与 const 对象一起工作,它应该这样说。 请考虑以下代码片段
:您可能会认为 (const) 引用在这里更合适,并为您提供相同的行为。 嗯,对。 只是给出了与我在其他地方看到的不同的图片......
I know the question is "a bit" outdated but as I came accross it somebody else may also do so in future... ...still I doubt the poor fellow will list down here to read my comment :)
It seems to me that we are still too confined to C-style way of thinking. In the OOP paradigma we play around with objects, not types. Const object may be conceptually different from a non-const object, specifically in the sense of logical-const (in contrast to bitwise-const). Thus even if const correctness of function params is (perhaps) an over-carefulness in case of PODs it is not so in case of objects. If a function works with a const object it should say so. Consider the following code snippet
ps.: you may argue that (const) reference would be more appropriate here and gives you the same behaviour. Well, right. Just giving a different picture from what I could see elsewhere...
我不会把 const 放在这样的参数上 - 每个人都知道布尔值(与 boolean& 相对)是常量,所以添加它会让人们思考“等等,什么?” 或者甚至您通过引用传递参数。
I wouldn't put const on parameters like that - everyone already knows that a boolean (as opposed to a boolean&) is constant, so adding it in will make people think "wait, what?" or even that you're passing the parameter by reference.
如果参数按值传递(并且不是引用),则该参数是否声明为 const 通常没有太大区别(除非它包含引用成员——这对于内置类型来说不是问题)。 如果参数是引用或指针,通常最好保护引用/指向的内存,而不是指针本身(我认为你不能使引用本身成为常量,但这并不重要,因为你不能改变引用者) 。
将所有可以保护的东西作为 const 似乎是个好主意。 如果参数只是 POD(包括内置类型)并且它们不可能进一步更改(例如,在您的示例中为 bool 参数),您可以省略它,而不必担心犯错误。
我不知道 .h/.cpp 文件声明差异,但它确实有一定意义。 在机器代码级别,没有什么是“const”的,因此如果将函数(在 .h 中)声明为非 const,则代码与将其声明为 const 相同(不考虑优化)。 但是,它可以帮助您让编译器确保您不会更改函数 (.ccp) 实现中的变量值。 当您从允许更改的接口继承但不需要更改参数来实现所需的功能时,它可能会很方便。
If the parameter is passed by value (and is not a reference), usually there is not much difference whether the parameter is declared as const or not (unless it contains a reference member -- not a problem for built-in types). If the parameter is a reference or pointer, it is usually better to protect the referenced/pointed-to memory, not the pointer itself (I think you cannot make the reference itself const, not that it matters much as you cannot change the referee).
It seems a good idea to protect everything you can as const. You can omit it without fear of making a mistake if the parameters are just PODs (including built-in types) and there is no chance of them changing further along the road (e.g. in your example the bool parameter).
I didn't know about the .h/.cpp file declaration difference, but it does make some sense. At the machine code level, nothing is "const", so if you declare a function (in the .h) as non-const, the code is the same as if you declare it as const (optimizations aside). However, it helps you to enlist the compiler that you will not change the value of the variable inside the implementation of the function (.ccp). It might come handy in the case when you're inheriting from an interface that allows change, but you don't need to change to parameter to achieve the required functionality.
总结一下:
std::vector::at(size_type pos)
。 对标准库来说足够好的对我来说也有好处。To summarize:
std::vector::at(size_type pos)
. What's good enough for the standard library is good for me.我倾向于尽可能使用 const。 (或目标语言的其他适当的关键字。)我这样做纯粹是因为它允许编译器进行额外的优化,否则它无法进行。 由于我不知道这些优化可能是什么,所以我总是这样做,即使它看起来很愚蠢。
据我所知,编译器很可能会看到一个 const 值参数,并说:“嘿,这个函数无论如何都不会修改它,所以我可以通过引用传递并节省一些时钟周期。” 我认为它永远不会做这样的事情,因为它改变了函数签名,但它说明了这一点。 也许它会执行一些不同的堆栈操作或其他操作...重点是,我不知道,但我确实知道尝试比编译器更聪明只会让我感到羞耻。
C++ 有一些额外的包袱,带有常量正确性的思想,因此它变得更加重要。
I tend to use const wherever possible. (Or other appropriate keyword for the target language.) I do this purely because it allows the compiler to make extra optimizations that it would not be able to make otherwise. Since I have no idea what these optimizations may be, I always do it, even where it seems silly.
For all I know, the compiler might very well see a const value parameter, and say, "Hey, this function isn't modifying it anyway, so I can pass by reference and save some clock cycles." I don't think it ever would do such a thing, since it changes the function signature, but it makes the point. Maybe it does some different stack manipulation or something... The point is, I don't know, but I do know trying to be smarter than the compiler only leads to me being shamed.
C++ has some extra baggage, with the idea of const-correctness, so it becomes even more important.
也许这不是一个有效的论点。 但是如果我们在函数内增加 const 变量的值,编译器将会给出一个错误:
“错误:只读参数增量”。 这意味着我们可以使用 const 关键字来防止意外修改函数内的变量(我们不应该这样做/只读)。 因此,如果我们在编译时不小心这样做了,编译器会让我们知道。 如果您不是唯一参与该项目的人,这一点尤其重要。
May be this wont be a valid argument. but if we increment the value of a const variable inside a function compiler will give us an error:
"error: increment of read-only parameter". so that means we can use const key word as a way to prevent accidentally modifying our variables inside functions(which we are not supposed to/read-only). so if we accidentally did it at the compile time compiler will let us know that. this is specially important if you are not the only one who is working on this project.
在您提到的情况下,它不会影响 API 的调用者,这就是为什么它不常见(并且在标头中没有必要)。 它只会影响你的功能的实现。
这并不是一件特别坏的事情,但好处并没有那么大,因为它不会影响你的 API,而且它会增加输入,所以通常不这样做。
In the case you mention, it doesn't affect callers of your API, which is why it's not commonly done (and isn't necessary in the header). It only affects the implementation of your function.
It's not particularly a bad thing to do, but the benefits aren't that great given that it doesn't affect your API, and it adds typing, so it's not usually done.
我不使用 const 作为传值参数。 调用者并不关心你是否修改参数,它是一个实现细节。
真正重要的是,如果方法不修改其实例,则将方法标记为 const。 边做边做,否则你可能会得到很多 const_cast<> 或很多 const_cast<> 。 或者您可能会发现将方法标记为 const 需要更改大量代码,因为它调用了本应标记为 const 的其他方法。
如果我不需要修改局部变量,我也倾向于将它们标记为 const。 我相信它可以通过更容易地识别“移动部分”来使代码更容易理解。
I do not use const for value-passed parametere. The caller does not care whether you modify the parameter or not, it's an implementation detail.
What is really important is to mark methods as const if they do not modify their instance. Do this as you go, because otherwise you might end up with either lots of const_cast<> or you might find that marking a method const requires changing a lot of code because it calls other methods which should have been marked const.
I also tend to mark local vars const if I do not need to modify them. I believe it makes the code easier to understand by making it easier to identify the "moving parts".
关于编译器优化:http://www.gotw.ca/gotw/081.htm
On compiler optimizations: http://www.gotw.ca/gotw/081.htm
如果可以的话我会使用const。 参数的 Const 意味着它们不应该改变它们的值。 这在通过引用传递时尤其有价值。 const for function 声明该函数不应更改类成员。
I use const were I can. Const for parameters means that they should not change their value. This is especially valuable when passing by reference. const for function declares that the function should not change the classes members.
当我以编写 C++ 代码为生时,我尽可能地使用了一切。 使用 const 是帮助编译器为您提供帮助的好方法。 例如,对方法返回值进行 const 操作可以避免拼写错误,例如:
当您的意思是:
如果 foo() 被定义为返回非常量引用:
编译器会很乐意让您为返回的匿名临时值分配一个值通过函数调用。 使其成为常量:
消除这种可能性。
When I coded C++ for a living I consted everything I possibly could. Using const is a great way to help the compiler help you. For instance, const-ing your method return values can save you from typos such as:
when you meant:
If foo() is defined to return a non-const reference:
The compiler will happily let you assign a value to the anonymous temporary returned by the function call. Making it const:
Eliminates this possibility.
在 comp.lang.c++.moderated 上的旧“本周大师”文章中对此主题进行了很好的讨论 此处。
相应的 GOTW 文章可在 Herb Sutter 的网站此处上找到。
There is a good discussion on this topic in the old "Guru of the Week" articles on comp.lang.c++.moderated here.
The corresponding GOTW article is available on Herb Sutter's web site here.
我在函数参数上使用 const,这些参数是引用(或指针),它们只是 [in] 数据,不会被函数修改。 意思是,使用引用的目的是为了避免复制数据并且不允许更改传递的参数。
在示例中将 const 放在布尔 b 参数上只会对实现施加约束,并且不会对类的接口做出贡献(尽管通常建议不更改参数)。
的函数签名
和
是相同的,这解释了您的 .c 和 .h
Asaf
I use const on function parameters that are references (or pointers) which are only [in] data and will not be modified by the function. Meaning, when the purpose of using a reference is to avoid copying data and not to allow changing the passed parameter.
Putting const on the boolean b parameter in your example only puts a constraint on the implementation and doesn't contribute for the class's interface (although not changing parameters is usually advised).
The function signature for
and
is the same, which explains your .c and .h
Asaf
我说const你的值参数。
考虑这个有缺陷的函数:
如果 number 参数是 const,编译器将停止并警告我们该错误。
I say const your value parameters.
Consider this buggy function:
If the number parameter was const, the compiler would stop and warn us of the bug.
如果您使用
->*
或.*
运算符,则这是必须的。它会阻止你写出像
我现在几乎所做的那样的东西,而且这可能不会达到你的意图。
我想说的是
,如果我在
Bar *
和p
之间放置一个const
,编译器就会告诉我这一点。If you use the
->*
or.*
operators, it's a must.It prevents you from writing something like
which I almost did right now, and which probably doesn't do what you intend.
What I intended to say was
and if I had put a
const
in betweenBar *
andp
, the compiler would have told me that.啊,一个艰难的。 一方面,声明是一个契约,按值传递 const 参数确实没有意义。 另一方面,如果您查看函数实现,如果您声明参数常量,则将为编译器提供更多优化机会。
Ah, a tough one. On one side, a declaration is a contract and it really does not make sense to pass a const argument by value. On the other hand, if you look at the function implementation, you give the compiler more chances to optimize if you declare an argument constant.
当参数按值传递时,const 毫无意义,因为您不会修改调用者的对象。
通过引用传递时应首选 const,除非函数的目的是修改传递的值。
最后,不修改当前对象(this)的函数可以而且可能应该声明为 const。 示例如下:
这是一个承诺,不会修改应用此调用的对象。 换句话说,您可以调用:
如果函数不是 const,这将导致编译器警告。
const is pointless when the argument is passed by value since you will not be modifying the caller's object.
const should be preferred when passing by reference, unless the purpose of the function is to modify the passed value.
Finally, a function which does not modify current object (this) can, and probably should be declared const. An example is below:
This is a promise to not modify the object to which this call is applied. In other words, you can call:
If the function was not const, this would result in a compiler warning.
将值参数标记为“const”绝对是一个主观的事情。
不过,我实际上更喜欢将值参数标记为 const,就像在您的示例中一样。
对我来说,价值在于清楚地表明函数参数值永远不会被函数更改。 它们在开始时和结束时具有相同的值。 对我来说,这是保持函数式编程风格的一部分。
对于一个短函数,在那里使用“const”可以说是浪费时间/空间,因为通常很明显参数没有被函数修改。
然而,对于较大的函数,它是实现文档的一种形式,并且由编译器强制执行。
我可以确定,如果我用“n”和“l”进行一些计算,我可以重构/移动该计算,而不必担心得到不同的结果,因为我错过了一个或两个都发生更改的地方。
由于它是实现细节,因此您不需要在标头中声明值参数 const,就像您不需要声明与实现使用的名称相同的函数参数一样。
Marking value parameters 'const' is definitely a subjective thing.
However I actually prefer to mark value parameters const, just like in your example.
The value to me is in clearly indicating that the function parameter values are never changed by the function. They will have the same value at the beginning as at the end. For me, it is part of keeping to a very functional programming sort of style.
For a short function, it's arguably a waste of time/space to have the 'const' there, since it's usually pretty obvious that the arguments aren't modified by the function.
However for a larger function, its a form of implementation documentation, and it is enforced by the compiler.
I can be sure if I make some computation with 'n' and 'l', I can refactor/move that computation without fear of getting a different result because I missed a place where one or both is changed.
Since it is an implementation detail, you don't need to declare the value parameters const in the header, just like you don't need to declare the function parameters with the same names as the implementation uses.
const 应该是 C++ 中的默认值。
像这样 :
const should have been the default in C++.
Like this :
1.根据我的评估,最佳答案:
@Adisak的答案 是根据我的评估的最佳答案。 请注意,这个答案在一定程度上是最好的,因为它也是最有真实代码示例支持的,除了使用声音和良好 -经过深思熟虑的逻辑。
2. 我自己的话(同意最佳答案):
const
没有任何好处。 它所做的只是:const
可能会阻碍这一点。const
会不必要地使代码变得混乱,到处都是const
,从而将注意力从真正需要安全的const
上转移开。代码。const
在需要时至关重要,并且必须使用,因为它可以防止函数外部持续更改带来的不良副作用,因此当参数仅作为输入时,每个指针或引用都必须使用 const ,不是输出。const
仅对通过引用或指针传递的参数使用具有额外的好处,可以使哪些参数是指针或引用非常明显。 需要强调的是,“小心!任何旁边有const
的参数都是引用或指针!”。3 Google 的话(同意我的观点和最佳答案):(
来自“Google C++ 风格指南")
资料来源:Google C++ 风格指南的“Const 的使用”部分:https://google .github.io/styleguide/cppguide.html#Use_of_const。 这实际上是一个非常有价值的部分,所以请阅读整个部分。
请注意,“TotW #109”代表 “本周提示 #109:有意义的
const
函数声明”,也是一本有用的读物。 它提供的信息更多,对要做什么的规定较少,并且基于上下文,早于上面引用的关于const
的 Google C++ 样式指南规则,但由于它提供了清晰度,上面引用的const
规则已添加到 Google C++ 样式指南中。另请注意,尽管我在这里引用 Google C++ 样式指南来捍卫我的立场,但这并不意味着我始终遵循该指南或始终建议遵循该指南。 他们推荐的一些东西实在是太奇怪了,例如他们的
kDaysInAWeek
“常量名称”风格的命名约定。 但是,指出世界上最成功和最有影响力的技术和软件公司之一使用与我和@Adisak等其他人相同的理由来支持我们对此事的观点仍然是有用和相关的。< /em>4. Clang 的 linter
clang-tidy
对此有一些选项:A. 还值得注意的是,Clang 的 linter
clang-tidy
有一个选项,readability-avoid-const-params-in-decls
,此处描述,以支持在代码库中强制执行不使用const
进行传递-值函数参数:为了完整和清晰起见,我自己添加了另外两个示例:
B.它还有此选项:
readability-const-return-type
- https://clang.llvm.org/extra/clang-tidy/checks/readability-const- return-type.html5. 我对此事如何编写风格指南的务实方法:
我只需将其复制并粘贴到我的风格指南中:
[复制/粘贴开始]
const
。 这样,当通过引用或指针传递的变量需要更改时就会变得很明显,因为它将缺少 const。 在此用例中,const
可防止函数外部发生意外副作用。const
,因为const
对调用者没有影响:即使变量发生更改函数内不会有函数外的副作用。 请参阅以下资源以获取更多理由和见解:const
”const
[即:按值传递的参数上的const
]不是定义(并且注意不要复制/粘贴无意义的const
)。它是没有意义的并且会被编译器忽略,它是视觉噪音,并且可能会误导读者”(< a href="https://abseil.io/tips/109" rel="noreferrer">https://abseil.io/tips/109,强调)。const
[即:按值传递的变量上的const
] 通过一个函数。const
由实现者决定,因为它有时很有用。clang-tidy
选项强制执行上述部分内容:以下是一些代码示例,用于演示上述
const
规则:const
参数示例:(有些是从这里借来的< /a>)
const
返回类型示例:(有些是从此处借用的)
[COPY/PASTE END]
关键字:函数参数中使用
const
; 编码标准; C 和 C++ 编码标准; 编码指南; 最佳实践; 代码标准; 常量返回值1. Best answer based on my assessment:
The answer by @Adisak is the best answer here based on my assessment. Note that this answer is in part the best because it is also the most well-backed-up with real code examples, in addition to using sound and well-thought-out logic.
2. My own words (agreeing with the best answer):
const
. All it does is:const
everywhere can hinder this.const
unnecessarily clutters the code withconst
s everywhere, drawing attention away from theconst
s that are truly necessary to have safe code.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 useconst
when the param is an input only, not an output. Usingconst
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 withconst
next to it is a reference or pointer!".3. Google's words (agreeing with me and the best answer):
(From the "Google C++ Style Guide")
Source: the "Use of const" section of the Google C++ Style Guide: https://google.github.io/styleguide/cppguide.html#Use_of_const. This is actually a really valuable section, so read the whole section.
Note that "TotW #109" stands for "Tip of the Week #109: Meaningful
const
in Function Declarations", and is also a useful read. It is more informative and less prescriptive on what to do, and based on context came before the Google C++ Style Guide rule onconst
quoted just above, but as a result of the clarity it provided, theconst
rule quoted just above was added to the Google C++ Style Guide.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's linter,
clang-tidy
, has some options for this:A. It's also worth noting that Clang's linter,
clang-tidy
, has an option,readability-avoid-const-params-in-decls
, described here, to support enforcing in a code base not usingconst
for pass-by-value function parameters:And here are two more examples I'm adding myself for completeness and clarity:
B. It also has this option:
readability-const-return-type
- https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html5. My pragmatic approach to how I'd word a style guide on the matter:
I'd simply copy and paste this into my style guide:
[COPY/PASTE START]
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 lackconst
. In this use caseconst
prevents accidental side effects outside the function.const
on function parameters passed by value, becauseconst
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:const
in Function Declarations"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 meaninglessconst
). It is meaningless and ignored by the compiler, it is visual noise, and it could mislead readers" (https://abseil.io/tips/109, emphasis added).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.const
[ie:const
on variables passed by value] on values returned by a function.const
on pointers or references returned by a function is up to the implementer, as it is sometimes useful.clang-tidy
options:Here are some code examples to demonstrate the
const
rules described above:const
Parameter Examples:(some are borrowed from here)
const
Return Type Examples:(some are borrowed from here)
[COPY/PASTE END]
Keywords: use of
const
in function parameters; coding standards; C and C++ coding standards; coding guidelines; best practices; code standards; const return values下面两行在功能上是等价的:
显然,如果以第二种方式定义的话,你将无法修改
foo
主体中的a
,但与外部。const 真正派上用场的是引用或指针参数:
这说明 foo 可以接受一个大参数,也许是一个千兆字节大小的数据结构,而不复制它。 此外,它还对调用者说:“Foo 不会*更改该参数的内容。” 传递 const 引用还允许编译器做出某些性能决策。
*:除非它抛弃了常量,但那是另一篇文章了。
The following two lines are functionally equivalent:
Obviously you won't be able to modify
a
in the body offoo
if it's defined the second way, but there's no difference from the outside.Where
const
really comes in handy is with reference or pointer parameters:What this says is that foo can take a large parameter, perhaps a data structure that's gigabytes in size, without copying it. Also, it says to the caller, "Foo won't* change the contents of that parameter." Passing a const reference also allows the compiler to make certain performance decisions.
*: Unless it casts away the const-ness, but that's another post.
错误。
这是关于自我记录你的代码和你的假设。
如果您的代码有很多人在处理,并且您的函数非常重要,那么您应该标记
const
任何可以标记的内容。 在编写工业强度的代码时,您应该始终假设您的同事都是精神病患者,试图以任何方式让您陷入困境(特别是因为将来通常是您自己)。此外,正如前面有人提到的,它可能可以帮助编译器优化一些东西(尽管可能性不大)。
Wrong.
It's about self-documenting your code and your assumptions.
If your code has many people working on it and your functions are non-trivial then you should mark
const
any and everything that you can. When writing industrial-strength code, you should always assume that your coworkers are psychopaths trying to get you any way they can (especially since it's often yourself in the future).Besides, as somebody mentioned earlier, it might help the compiler optimize things a bit (though it's a long shot).
原因是参数的 const 仅适用于函数内部,因为它正在处理数据的副本。 这意味着函数签名实际上是相同的。 不过,经常这样做可能是不好的风格。
我个人倾向于不使用 const,除了引用和指针参数。 对于复制的对象来说,这并不重要,尽管它可以更安全,因为它表明了函数内的意图。 这确实是一个判断力。 尽管在循环某些内容时我确实倾向于使用 const_iterator 并且我不打算修改它,所以我想每个人都有自己的想法,只要
const
正确性供参考类型得到严格维护。The reason is that
const
for the parameter only applies locally within the function, since it is working on a copy of the data. This means the function signature is really the same anyways. It's probably bad style to do this a lot though.I personally tend to not use
const
except for reference and pointer parameters. For copied objects it doesn't really matter, although it can be safer as it signals intent within the function. It's really a judgement call. I do tend to useconst_iterator
though when looping on something and I don't intend on modifying it, so I guess to each his own, as long asconst
correctness for reference types is rigorously maintained.有时(太频繁了!)我必须整理别人的 C++ 代码。 我们都知道,别人的 C++ 代码几乎从定义上来说就是一团糟:) 因此,我破译本地数据流的第一件事就是在每个变量定义中放入 const直到编译器开始咆哮。 这也意味着 const 限定值参数,因为它们只是由调用者初始化的精美局部变量。
啊,我希望变量默认是 const ,并且非 const 变量需要 mutable :)
Sometimes (too often!) I have to untangle someone else's C++ code. And we all know that someone else's C++ code is a complete mess almost by definition :) So the first thing I do to decipher local data flow is put const in every variable definition until compiler starts barking. This means const-qualifying value arguments as well, because they are just fancy local variables initialized by caller.
Ah, I wish variables were const by default and mutable was required for non-const variables :)
从 API 的角度来看,额外的多余 const 是不好的:
在代码中为按值传递的内部类型参数放置额外的多余 const 使 API 变得混乱,同时对调用者或 API 用户没有做出任何有意义的承诺(这只是妨碍了实施)。
API 中太多不需要的“const”就像“狼来了”,最终人们会开始忽略“const”,因为它无处不在,而且大多数时候没有任何意义。
API 中额外 const 的“reductio adabsurdum”参数对于前两点是有好处的,如果更多 const 参数是好的,那么每个可以有 const 的参数都应该有一个 const。 事实上,如果它真的那么好,您会希望 const 成为参数的默认值,并且仅当您想要更改参数时才使用“mutable”之类的关键字。
因此,让我们尝试在任何可能的地方放入 const:
考虑上面的代码行。 不仅声明更加混乱、更长、更难阅读,而且 API 用户可以安全地忽略四个“const”关键字中的三个。 然而,额外使用“const”使得第二行可能危险!
为什么?
快速误读第一个参数 char * const buffer 可能会让您认为它不会修改传入的数据缓冲区中的内存 - 然而,事实并非如此! 当快速浏览或误读时,多余的“const”可能会导致对您的 API 做出危险且不正确的假设。
从代码实现的角度来看,多余的 const 也是不好的:
如果 FLEXIBLE_IMPLMENTATION 不为 true,则 API “承诺”不会按照下面的第一种方式实现该函数。
这是一个非常愚蠢的承诺。 为什么你要做出一个对你的调用者没有任何好处并且只会限制你的实现的承诺呢?
这两个都是同一函数的完全有效的实现,因此您所做的一切都是不必要地把一只手绑在背后。
此外,这是一个非常肤浅的承诺,很容易(并且可以合法地规避)。
看,我无论如何都以这种方式实现了它,尽管我承诺不这样做——只是使用包装函数。 这就像电影中坏人承诺不杀人,却命令他的追随者去杀掉他们一样。
那些多余的常量的价值不亚于电影坏人的承诺。
但说谎的能力变得更糟:
我发现你可以通过使用虚假 const 来使标头(声明)和代码(定义)中的 const 不匹配。 支持 const 的拥护者声称这是一件好事,因为它允许您仅在定义中添加 const。
然而,反之亦然……您可以仅在声明中放置一个虚假常量,并在定义中忽略它。 这只会让 API 中多余的 const 变得更可怕,更可怕的谎言 - 请看这个例子:
所有多余的 const 实际上所做的就是通过强迫实现者在需要时使用另一个本地副本或包装函数来降低实现者的代码的可读性。更改变量或通过非常量引用传递变量。
看这个例子。 哪个更具可读性? 很明显,第二个函数中额外变量的唯一原因是因为某些 API 设计者添加了多余的 const 吗?
希望我们在这里学到了一些东西。 多余的 const 是 API 混乱的碍眼者、烦人的唠叨者、肤浅而无意义的承诺、不必要的障碍,并且偶尔会导致非常危险的错误。
Extra Superfluous const are bad from an API stand-point:
Putting extra superfluous const's in your code for intrinsic type parameters passed by value clutters your API while making no meaningful promise to the caller or API user (it only hampers the implementation).
Too many 'const' in an API when not needed is like "crying wolf", eventually people will start ignoring 'const' because it's all over the place and means nothing most of the time.
The "reductio ad absurdum" argument to extra consts in API are good for these first two points would be is if more const parameters are good, then every argument that can have a const on it, SHOULD have a const on it. In fact, if it were truly that good, you'd want const to be the default for parameters and have a keyword like "mutable" only when you want to change the parameter.
So lets try putting in const whereever we can:
Consider the line of code above. Not only is the declaration more cluttered and longer and harder to read but three of the four 'const' keywords can be safely ignored by the API user. However, the extra use of 'const' has made the second line potentially DANGEROUS!
Why?
A quick misread of the first parameter
char * const buffer
might make you think that it will not modify the memory in data buffer that is passed in -- however, this is not true! Superfluous 'const' can lead to dangerous and incorrect assumptions about your API when scanned or misread quickly.Superfluous const are bad from a Code Implementation stand-point as well:
If FLEXIBLE_IMPLEMENTATION is not true, then the API is “promising” not to implement the function the first way below.
That’s a very silly promise to make. Why should you make a promise that gives no benefit at all to your caller and only limits your implementation?
Both of these are perfectly valid implementations of the same function though so all you’ve done is tied one hand behind your back unnecessarily.
Furthermore, it’s a very shallow promise that is easily (and legally circumvented).
Look, I implemented it that way anyhow even though I promised not to – just using a wrapper function. It’s like when the bad guy promises not to kill someone in a movie and orders his henchman to kill them instead.
Those superfluous const’s are worth no more than a promise from a movie bad-guy.
But the ability to lie gets even worse:
I have been enlightened that you can mismatch const in header (declaration) and code (definition) by using spurious const. The const-happy advocates claim this is a good thing since it lets you put const only in the definition.
However, the converse is true... you can put a spurious const only in the declaration and ignore it in the definition. This only makes superfluous const in an API more of a terrible thing and a horrible lie - see this example:
All the superfluous const actually does is make the implementer's code less readable by forcing him to use another local copy or a wrapper function when he wants to change the variable or pass the variable by non-const reference.
Look at this example. Which is more readable ? Is it obvious that the only reason for the extra variable in the second function is because some API designer threw in a superfluous const ?
Hopefully we've learned something here. Superfluous const is an API-cluttering eyesore, an annoying nag, a shallow and meaningless promise, an unnecessary hindrance, and occasionally leads to very dangerous mistakes.