提问人:Rob 提问时间:9/23/2008 最后编辑:user16217248Rob 更新时间:10/19/2023 访问量:386290
对函数参数使用 const 有什么影响吗?为什么不影响函数签名?
Does using const on function parameters have any effect? Why does it not affect the function signature?
问:
例如,假设一个简单的赋值器接受单个布尔参数:
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
我个人倾向于不使用引用和指针参数。对于复制的对象,这并不重要,尽管它可能更安全,因为它在函数中发出意图信号。这真的是一个判断电话。我确实倾向于在循环某些东西时使用 though,并且我不打算修改它,所以我猜每个人都有自己的,只要严格维护引用类型的正确性。const
const_iterator
const
评论
const
const
const
const
int getDouble(int a){ ++a; return 2*a; }
试试这个。当然,这与此无关,但它可以在多个程序员在很长一段时间内编写的长函数中找到。我强烈建议编写在查找时会产生编译错误的编写。++a
int getDouble( const int a ){ //... }
++a;
class Foo { int multiply(int a, int b) const; }
a
b
int Foo::multiply(const int a, const int b) const { }
Foo
我对函数参数使用 const,这些参数是引用(或指针),这些参数只是 [in] 数据,不会被函数修改。这意味着,当使用引用的目的是避免复制数据并且不允许更改传递的参数时。
在示例中,将 const 放在布尔值 b 参数上只会对实现施加约束,并且不会对类的接口产生影响(尽管通常建议不要更改参数)。
函数签名
void foo(int a);
和
void foo(const int a);
是一样的,这解释了你的 .c 和 .h
阿萨夫
在你提到的情况下,它不会影响你的 API 的调用者,这就是为什么它不经常这样做(并且在标头中不是必需的)。它只影响函数的实现。
这并不是一件特别坏的事情,但好处并不是那么大,因为它不会影响你的 API,而且它增加了类型,所以通常不会这样做。
我不会把 const 放在这样的参数上——每个人都已经知道布尔值(而不是布尔值&)是常量,所以添加它会让人们认为“等等,什么?”,甚至你正在通过引用传递参数。
评论
要记住的一点是,从一开始就让事情变得 const 比以后再尝试把它们放进去要容易得多。
当您希望某些内容保持不变时,请使用 const - 它是一个附加提示,用于描述您的函数的作用和预期内容。我见过许多可以与其中一些一起使用的 C API,尤其是那些接受 c 字符串的 API !
我更倾向于在 cpp 文件中省略 const 关键字而不是标头,但是由于我倾向于剪切+粘贴它们,因此它们将保留在两个位置。我不知道为什么编译器允许这样做,我想这是编译器的事情。最佳做法肯定是将 const 关键字放在两个文件中。
评论
啊,一个艰难的。一方面,声明是契约,按值传递常量参数确实没有意义。另一方面,如果你看一下函数实现,如果你声明一个参数常量,你就会给编译器更多的优化机会。
示例中的所有常量都没有目的。默认情况下,C++ 是按值传递的,因此该函数会获取这些 int 和 boolean 的副本。即使函数修改了它们,调用方的副本也不会受到影响。
所以我会避免额外的常量,因为
- 它们是多余的
- 他们杂乱无章 正文
- 他们阻止我 更改传入的值 它可能有用或有效的情况。
评论
They prevent me from changing the passed in value in cases where it might be useful or efficient.
- 但这正是您可能希望在函数定义中将参数标记为 const 的原因(而不是声明!):以指示参数(现在是局部变量)不会更改。非常量参数可能指示您的实现计划更改局部变量。
实际上没有理由将值参数设置为“const”,因为该函数无论如何都只能修改变量的副本。
使用“const”的原因是,如果你通过引用传递更大的东西(例如,一个有很多成员的结构体),在这种情况下,它确保函数不能修改它;或者更确切地说,如果您尝试以传统方式修改它,编译器会抱怨。它可以防止它被意外修改。
我尽可能使用 const。参数的常量意味着它们不应更改其值。这在通过引用传递时尤其有价值。const for function 声明函数不应更改类成员。
我不将 const 用于值传递的参数。调用方不关心你是否修改参数,这是一个实现细节。
真正重要的是,如果方法不修改其实例,则将其标记为 const。边走边做,否则你最终可能会得到很多const_cast<>或者你可能会发现标记一个方法const需要更改大量代码,因为它调用了其他应该被标记为const的方法。
如果我不需要修改它们,我也倾向于标记本地变量 const。我相信它使代码更容易识别“移动部件”,从而使代码更容易理解。
Const 参数仅在参数通过引用(即引用或指针)传递时才有用。当编译器看到 const 参数时,它会确保参数中使用的变量不会在函数体中被修改。为什么有人想将 by-value 参数设置为常量?:-)
评论
const
const
如果参数是按值传递的(并且不是引用),则通常参数是否声明为 const 没有太大区别(除非它包含引用成员 - 对于内置类型来说不是问题)。如果参数是引用或指针,通常最好保护引用/指向的内存,而不是指针本身(我认为你不能使引用本身成为常量,这并不重要,因为你不能改变引用)。 保护一切似乎是个好主意。如果参数只是 POD(包括内置类型),并且它们不会进一步更改(例如,在您的示例中为 bool 参数),则可以省略它而不必担心出错。
我不知道 .h/.cpp 文件声明的差异,但它确实有一定意义。在机器代码级别,没有什么是“const”的,所以如果你将一个函数(在 .h 中)声明为非常量,则代码与将其声明为 const 是一样的(除了优化)。但是,它可以帮助您登记编译器,以确保您不会更改函数 (.ccp) 实现中的变量值。当您从允许更改的接口继承时,它可能会派上用场,但您不需要更改参数即可实现所需的功能。
我倾向于尽可能使用 const。(或目标语言的其他适当关键字。我这样做纯粹是因为它允许编译器进行额外的优化,否则它将无法进行。由于我不知道这些优化可能是什么,所以我总是这样做,即使看起来很傻。
据我所知,编译器很可能会看到一个 const value 参数,然后说,“嘿,这个函数无论如何都不会修改它,所以我可以通过引用传递并保存一些时钟周期。我不认为它会做这样的事情,因为它改变了函数签名,但它说明了这一点。也许它做了一些不同的堆栈操作或其他东西......关键是,我不知道,但我知道试图比编译器更聪明只会导致我感到羞耻。
C++有一些额外的包袱,具有常量正确性的想法,因此它变得更加重要。
评论
const
const
以下两行在功能上是等效的:
int foo (int a);
int foo (const int a);
显然,如果以第二种方式定义,您将无法在正文中进行修改,但与外部没有区别。a
foo
真正派上用场的是引用或指针参数:const
int foo (const BigStruct &a);
int foo (const BigStruct *a);
这说明,foo 可以接受一个大参数,也许是一个千兆字节大小的数据结构,而无需复制它。此外,它还对调用方说,“Foo 不会*更改该参数的内容。传递 const 引用还允许编译器做出某些性能决策。
*:除非它抛弃了恒常性,但那是另一篇帖子。
评论
当参数按值传递时,const 毫无意义,因为您不会修改调用方的对象。
通过引用传递时,应首选 const,除非函数的目的是修改传递的值。
最后,一个不修改当前对象 (this) 的函数可以并且可能应该声明为 const。示例如下:
int SomeClass::GetValue() const {return m_internalValue;}
这是不修改应用此调用的对象的承诺。换句话说,您可以调用:
const SomeClass* pSomeClass;
pSomeClass->GetValue();
如果函数不是 const,则会导致编译器警告。
当参数按值传递时,
const
是没有意义的,因为你会 不得修改调用方的对象。
错。
这是关于自我记录你的代码和你的假设。
如果你的代码有很多人在处理它,并且你的函数是非平凡的,那么你应该标记任何你能标记的东西。在编写工业级代码时,你应该始终假设你的同事是精神病患者,他们试图以任何可能的方式让你(特别是因为将来通常是你自己)。const
此外,正如前面提到的,它可能有助于编译器进行一些优化(尽管这是一个很长的镜头)。
评论
有时(太频繁了!我必须解开别人的 C++ 代码。我们都知道,别人的C++代码几乎从定义上讲是一团糟:)因此,我破译本地数据流的第一件事是将 const 放在每个变量定义中,直到编译器开始吠叫。这也意味着 const 限定值参数,因为它们只是调用者初始化的花哨局部变量。
啊,我希望变量默认是常量,非常量变量需要可变:)
评论
当我以编写 C++ 为生时,我尽我所能。使用 const 是帮助编译器帮助你的好方法。例如,对方法返回值进行设置可以使您免于拼写错误,例如:
foo() = 42
当你的意思是:
foo() == 42
如果 foo() 被定义为返回非常量引用:
int& foo() { /* ... */ }
编译器很乐意让您为函数调用返回的匿名临时值赋值。使其常量:
const int& foo() { /* ... */ }
消除了这种可能性。
评论
foo() = 42
const int foo()
int foo()
const int& foo()
int foo()
将值参数标记为“const”绝对是一件主观的事情。
但是,我实际上更喜欢将值参数标记为 const,就像在您的示例中一样。
void func(const int n, const long l) { /* ... */ }
对我来说,值清楚地表明函数参数值永远不会被函数更改。它们在开始时和结束时具有相同的值。对我来说,这是保持非常实用的编程风格的一部分。
对于一个短函数来说,将“const”放在那儿可以说是浪费时间/空间,因为通常很明显参数不会被函数修改。
但是,对于较大的函数,它是一种实现文档形式,由编译器强制执行。
我可以肯定,如果我用“n”和“l”进行一些计算,我可以重构/移动该计算,而不必担心得到不同的结果,因为我错过了一个或两个都发生了变化的地方。
由于它是实现细节,因此无需在标头中声明值参数 const,就像不需要声明与实现使用的名称相同的函数参数一样。
由于参数是按值传递的,因此从调用函数的角度来看,是否指定 const 没有任何区别。基本上,将按值传递参数声明为 const 没有任何意义。
const 应该是 C++ 中的默认值。 喜欢这个:
int i = 5 ; // i is a constant
var int i = 5 ; // i is a real variable
评论
unsigned
int i = 5; // i is unsigned
signed int i = 5; // i is signed
我说const你的值参数。
考虑这个有缺陷的函数:
bool isZero(int number)
{
if (number = 0) // whoops, should be number == 0
return true;
else
return false;
}
如果 number 参数是 const,编译器将停止并警告我们该错误。
评论
在comp.lang.c++.moderated上的旧“本周大师”文章中,有关于这个话题的很好的讨论。
相应的 GOTW 文章可在 Herb Sutter 的网站上找到。
评论
关于编译器优化:http://www.gotw.ca/gotw/081.htm
从 API 的角度来看,额外的多余常量是不好的:
在代码中为按值传递的内部类型参数添加额外的多余常量会使 API 混乱,同时不会对调用者或 API 用户做出有意义的承诺(这只会阻碍实现)。
当不需要时,API 中过多的“const”就像“狼来了”,最终人们会开始忽略“const”,因为它无处不在,而且大多数时候没有任何意义。
API 中额外常量的“reductio ad absurdum”参数对前两点有好处,如果更多的 const 参数是好的,那么每个可以有 const 的参数都应该有一个 const。事实上,如果它真的那么好,你会希望 const 成为参数的默认值,并且只有在你想更改参数时才使用像 “mutable” 这样的关键字。
因此,让我们尝试尽可能地放入常量:
void mungerum(char * buffer, const char * mask, int count);
void mungerum(char * const buffer, const char * const mask, const int count);
考虑上面的代码行。不仅声明更杂乱、更长、更难阅读,而且 API 用户可以安全地忽略四个“const”关键字中的三个。然而,“const”的额外使用使第二行具有潜在的危险性!
为什么?
对第一个参数的快速误读可能会使您认为它不会修改传入的数据缓冲区中的内存 - 但是,事实并非如此!多余的“const”在快速扫描或误读时会导致对 API 的危险和不正确的假设。char * const buffer
从代码实现的角度来看,多余的常量也是不好的:
#if FLEXIBLE_IMPLEMENTATION
#define SUPERFLUOUS_CONST
#else
#define SUPERFLUOUS_CONST const
#endif
void bytecopy(char * SUPERFLUOUS_CONST dest,
const char *source, SUPERFLUOUS_CONST int count);
如果FLEXIBLE_IMPLEMENTATION不成立,则 API “承诺”不会以以下第一种方式实现该功能。
void bytecopy(char * SUPERFLUOUS_CONST dest,
const char *source, SUPERFLUOUS_CONST int count)
{
// Will break if !FLEXIBLE_IMPLEMENTATION
while(count--)
{
*dest++=*source++;
}
}
void bytecopy(char * SUPERFLUOUS_CONST dest,
const char *source, SUPERFLUOUS_CONST int count)
{
for(int i=0;i<count;i++)
{
dest[i]=source[i];
}
}
这是一个非常愚蠢的承诺。你为什么要做出一个承诺,对你的来电者没有任何好处,只会限制你的实施?
不过,这两者都是同一函数的完全有效实现,因此您所做的只是不必要地将一只手绑在背后。
此外,这是一个非常肤浅的承诺,很容易(并且在法律上被规避)。
inline void bytecopyWrapped(char * dest,
const char *source, int count)
{
while(count--)
{
*dest++=*source++;
}
}
void bytecopy(char * SUPERFLUOUS_CONST dest,
const char *source,SUPERFLUOUS_CONST int count)
{
bytecopyWrapped(dest, source, count);
}
看,无论如何,我都以这种方式实现了它,即使我答应不这样做——只是使用包装器函数。这就像坏人承诺不会在电影中杀死某人并命令他的追随者杀死他们一样。
那些多余的常量只不过是电影坏人的承诺。
但撒谎的能力变得更糟:
我被启发了,你可以通过使用虚假的const在header(声明)和代码(定义)中不匹配const。const-happy 的拥护者声称这是一件好事,因为它让你只把 const 放在定义中。
// Example of const only in definition, not declaration
struct foo { void test(int *pi); };
void foo::test(int * const pi) { }
然而,反之亦然......您只能在声明中放置虚假的常量,而在定义中忽略它。这只会让 API 中多余的常量变得更加可怕和可怕的谎言 - 请参阅以下示例:
struct foo
{
void test(int * const pi);
};
void foo::test(int *pi) // Look, the const in the definition is so superfluous I can ignore it here
{
pi++; // I promised in my definition I wouldn't modify this
}
实际上,所有多余的 const 所做的就是在实现者想要更改变量或通过非常量引用传递变量时,通过强制他使用另一个本地副本或包装函数来降低实现者的代码的可读性。
请看这个例子。哪个更具可读性?很明显,第二个函数中出现额外变量的唯一原因是因为某些 API 设计者抛入了一个多余的常量?
struct llist
{
llist * next;
};
void walkllist(llist *plist)
{
llist *pnext;
while(plist)
{
pnext=plist->next;
walk(plist);
plist=pnext; // This line wouldn't compile if plist was const
}
}
void walkllist(llist * SUPERFLUOUS_CONST plist)
{
llist * pnotconst=plist;
llist *pnext;
while(pnotconst)
{
pnext=pnotconst->next;
walk(pnotconst);
pnotconst=pnext;
}
}
希望我们在这里学到了一些东西。多余的常量是 API 杂乱无章的碍眼,是烦人的唠叨,是肤浅而无意义的承诺,是不必要的障碍,偶尔会导致非常危险的错误。
评论
void foo(int)
void foo(const int)
pi++
如果您使用 or 运算符,则必须这样做。->*
.*
它阻止你写类似的东西
void foo(Bar *p) { if (++p->*member > 0) { ... } }
我现在几乎做到了,而且可能没有达到你的意图。
我想说的是
void foo(Bar *p) { if (++(p->*member) > 0) { ... } }
如果我在 和 之间放一个,编译器会告诉我。const
Bar *
p
评论
也许这不是一个有效的论点。但是,如果我们在函数编译器中增加 const 变量的值,则会给我们一个错误: “错误:只读参数的增量”。因此,这意味着我们可以使用 const 关键字来防止意外修改函数中的变量(我们不应该/只读)。因此,如果我们在编译时不小心这样做了,编译器会让我们知道这一点。如果您不是唯一从事此项目的人,这一点尤其重要。
我知道这个问题“有点”过时了,但当我遇到它时,其他人将来可能也会这样做......我仍然怀疑这个可怜的家伙会在这里列出来阅读我的评论:)
在我看来,我们仍然过于局限于C风格的思维方式。在 OOP 范式中,我们玩的是对象,而不是类型。const 对象在概念上可能与非 const 对象不同,特别是在逻辑 const 的意义上(与按位 const 相反)。因此,即使函数参数的 const 正确性(也许)在 POD 的情况下过于谨慎,但在对象的情况下却不是这样。如果一个函数与一个 const 对象一起工作,它应该这样说。请考虑以下代码片段
#include <iostream>
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SharedBuffer {
private:
int fakeData;
int const & Get_(int i) const
{
std::cout << "Accessing buffer element" << std::endl;
return fakeData;
}
public:
int & operator[](int i)
{
Unique();
return const_cast<int &>(Get_(i));
}
int const & operator[](int i) const
{
return Get_(i);
}
void Unique()
{
std::cout << "Making buffer unique (expensive operation)" << std::endl;
}
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void NonConstF(SharedBuffer x)
{
x[0] = 1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ConstF(const SharedBuffer x)
{
int q = x[0];
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main()
{
SharedBuffer x;
NonConstF(x);
std::cout << std::endl;
ConstF(x);
return 0;
}
PS.:你可能会争辩说(const)引用在这里更合适,并且给你相同的行为。嗯,对。只是给出了与我在其他地方看到的不同的画面......
作为一个 VB.NET 程序员,需要使用具有 50+ 公开函数的 C++ 程序,以及偶尔使用 const 限定符的 .h 文件,很难知道何时使用 ByRef 或 ByVal 访问变量。
当然,程序通过在你犯错的行上生成异常错误来告诉你,但随后你需要猜测 2-10 个参数中的哪一个是错误的。
因此,现在我有一个令人反感的任务,即试图说服开发人员,他们应该以一种允许轻松创建所有 VB.NET 函数定义的自动化方法的方式真正定义他们的变量(在 .h 文件中)。然后他们会得意地说,“阅读......文档。
我编写了一个 awk 脚本来解析 .h 文件,并创建所有 Declare Function 命令,但是没有指示哪些变量是 R/O 与 R/W,它只完成了一半的工作。
编辑:
在另一位用户的鼓励下,我添加了以下内容;
下面是一个 (IMO) 格式不佳的 .h 条目示例;
typedef int (EE_STDCALL *Do_SomethingPtr)( int smfID, const char* cursor_name, const char* sql );
我的脚本生成的 VB;
Declare Function Do_Something Lib "SomeOther.DLL" (ByRef smfID As Integer, ByVal cursor_name As String, ByVal sql As String) As Integer
请注意第一个参数上缺少的“const”。没有它,程序(或其他开发人员)不知道第一个参数应该被传递“ByVal”。通过添加“const”,它使 .h 文件自记录,以便使用其他语言的开发人员可以轻松编写工作代码。
评论
*.h
const
int smfID
const int smfID
int& smfID
总结一下:
- “通常情况下,const pass-by-value 充其量是无用的,而且具有误导性。”从 GOTW006
- 但是,您可以像使用变量一样将它们添加到.cpp中。
- 请注意,标准库不使用 const。对标准库来说足够好的东西对我有好处。
std::vector::at(size_type pos)
评论
_Tmp
1. 根据我的评估的最佳答案:
根据我的评估,@Adisak的答案是这里最好的答案。请注意,这个答案在一定程度上是最好的,因为它也是最有真实代码示例支持的答案,此外还使用了合理且经过深思熟虑的逻辑。
2. 我自己的话(同意最佳答案):
- 对于按值传递,添加 .它所做的只是:
const
- 限制实现者每次想要更改源代码中的输入参数时都必须制作一个副本(无论如何,这种更改都不会产生副作用,因为传入的内容已经是副本,因为它是按值传递的)。通常,更改按值传递的输入参数用于实现函数,因此到处添加可能会阻碍这一点。
const
- 并且添加不必要的代码会使代码与 S 无处不在,从而将注意力从拥有安全代码真正必要的 S 上移开。
const
const
const
- 限制实现者每次想要更改源代码中的输入参数时都必须制作一个副本(无论如何,这种更改都不会产生副作用,因为传入的内容已经是副本,因为它是按值传递的)。通常,更改按值传递的输入参数用于实现函数,因此到处添加可能会阻碍这一点。
- 然而,在处理指针或引用时,在需要时至关重要,并且必须使用,因为它可以防止函数外部的持续更改产生不必要的副作用,因此当参数仅是输入而不是输出时,必须使用每个指针或引用。仅对通过引用或指针传递的参数使用还有一个额外的好处,即可以非常清楚地了解哪些参数是指针或引用。坚持说“小心!任何旁边的参数都是引用或指针!
const
const
const
const
- 我上面描述的通常是我工作过的专业软件组织达成的共识,并被认为是最佳实践。有时,这条规则甚至很严格:“永远不要对按值传递的参数使用 const,但如果它们只是输入,则始终在通过引用或指针传递的参数上使用 const。
3.谷歌的话(同意我和最好的答案):
(摘自“Google C++ 风格指南")
对于按值传递的函数参数,const 对调用方没有影响,因此不建议在函数声明中使用。请参阅 TotW #109。
既不鼓励也不鼓励对局部变量使用 const。
资料来源:Google C++风格指南的“常量的使用”部分:https://google.github.io/styleguide/cppguide.html#Use_of_const。这实际上是一个非常有价值的部分,因此请阅读整个部分。
请注意,“TotW #109”代表“本周提示 #109:函数声明中的有意义的常量
”,也是一本有用的读物。它提供了更多的信息,而不是关于做什么的规范性,并且基于上下文,在上面引用的 Google C++ 风格指南规则之前,但由于它提供的清晰度,上面引用的规则被添加到 Google C++ 风格指南中。const
const
另请注意,即使我在这里引用Google C++风格指南来捍卫我的立场,这并不意味着我总是遵循指南或总是建议遵循指南。他们推荐的一些东西很奇怪,比如他们针对“常量名称”的 kDaysInAWeek
样式命名约定。然而,当世界上最成功和最有影响力的技术和软件公司之一使用与我和其他类似@Adisak相同的理由来支持我们在这个问题上的观点时,仍然有用和相关。
4. Clang 的 linter, , 对此有一些选择:clang-tidy
一个。还值得注意的是,Clang 的 linter 有一个选项,此处描述,用于支持在代码库中强制执行不使用 const
作为按值传递函数参数:clang-tidy
readability-avoid-const-params-in-decls
检查函数声明是否具有顶级 const 参数。
声明中的 const 值不会影响函数的签名,因此不应将它们放在那里。
例子:
void f(const string); // Bad: const is top level. void f(const 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]
B.它还具有此选项: - https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.htmlreadability-const-return-type
5. 我务实地对待如何就此事撰写风格指南:
我只需将其复制并粘贴到我的风格指南中:
[复制/粘贴开始]
- 当函数参数的内容(它们指向的内容)不打算更改时,请始终使用通过引用或指针传递的函数参数。这样,当通过引用或指针传递的变量 IS 被更改时,它就变得很明显了,因为它将缺少 .在此用例中,可防止函数外部的意外副作用。
const
const
const
- 不建议在按值传递的函数参数上使用,因为对调用方没有影响:即使在函数中更改了变量,也不会在函数之外产生副作用。有关其他理由和见解,请参阅以下资源:
const
const
- "切勿在非定义的声明中对函数参数使用顶级 [ie: on parameters by value] (并注意不要复制/粘贴无意义的 )。它毫无意义,被编译器忽略了,它是视觉噪音,它可能会误导读者“(https://abseil.io/tips/109,强调后加)。
const
const
const
- 唯一对编译有影响的限定符是放置在函数定义中的限定符,而不是函数正向声明中的限定符,例如头文件中的函数(方法)声明中的限定符。
const
- 切勿对函数返回的值使用顶级 [ie: on variables passing by value]。
const
const
- 使用函数返回的 on 指针或引用取决于实现者,因为它有时很有用。
const
- TODO:使用以下选项强制执行上述某些操作:
clang-tidy
- 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
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]
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();
[复制/粘贴结束]
关键词:常量
在函数参数中的应用;编码标准;C 和 C++ 编码标准;编码指南;最佳做法;代码标准;const 返回值
评论