当学习C++时,学习函数概念的第一步通常是类似以下内容的函数:
int add(int a, int b)
{
return a+b;
}
现在我在想:我应该在这里使用const
关键字,还是不用它,从而导致...
int add(const int a, const int b)
{
return a+b;
}
但这样做有意义吗?它会加速我的程序,做其他重要的事情,还是只会增加混乱?
当学习C++时,学习函数概念的第一步通常是类似以下内容的函数:
int add(int a, int b)
{
return a+b;
}
现在我在想:我应该在这里使用const
关键字,还是不用它,从而导致...
int add(const int a, const int b)
{
return a+b;
}
但这样做有意义吗?它会加速我的程序,做其他重要的事情,还是只会增加混乱?
从调用者的角度来看,第一种和第二种形式是相同的。
由于整数是通过值传递的,即使函数修改了a
和b
,修改后的值也是原始值的副本,对于调用者来说不可见。
然而,从函数实现者的角度来看,存在差异。实际上,在第二种形式中:
如果你尝试在函数体内修改标记为
int add(const int a, const int b)
const
的a
和b
的值,你将会收到编译错误。
相反,如果省略const
,则可以更改这些值。再次强调,这些修改不会对调用者可见。
const
。它不是函数签名的一部分。这就是我认为对于这些简单函数不包括它的主要原因,因为从调用者的角度来看,它并不存在,只是一个实现细节:对于这样一个简单的函数,它是一个不必要的复杂性。 - Martin Baint add(const int a, const int b)
表示在函数体内不能修改输入参数。
也许编译器可以基于此进行一些优化,因此它应该永远不会比非const
等效版本更慢。但我从未在实践中观察到这种效果。const
参数还可以增加代码库的稳定性,特别是在协作项目中。int add(int a, int b)
。极少数情况下,对于特别长的函数,我会利用可以使用非const
参数声明函数,并使用const
参数定义函数的事实。我感觉每个人都在绕过答案的这个部分......
使用const
确实可以防止函数在内部修改您的int a
和b
的值。这非常有用,因此如果编译器允许,请随意使用它。但是,函数调用者一旦函数完成就无法知道a
和b
的任何变化。因此,即使a
和b
已更改,除了定义函数的人以外,没有人会知道它们的更新值。
int funcB(int a, int b)
{
a = a+1;
b = b*b;
return a+b;
}
void funcA()
{
int s = 5;
int t = 6;
int result = funcB(s, t);
printf("%f + %f = %f", s,t, result);
}
funcA 打印出:"5 + 6 = 42"
Const
保护通常在通过引用传递值时使用,例如:
int function(const int &a, const int &b) {}
这将变量 a
和 b
的引用传递给函数(即不复制 a
和 b
,而是仅传递该变量的内存地址,也称为句柄)。当通过引用传递变量时,对变量所做的任何更改都会在函数范围之外记忆,并且可能会改变程序运行的方式。这通常是不期望的行为。
因此,如果您重新设计上面的 funcB
并通过引用传递:
int funcB(int &a, int &b)
{
a = a+1;
b = b*b;
return a+b;
}
funcA 输出:"6 + 36 = 42"
如果你在 funcB
中添加了 const
的正确性:
int funcB(const int &a, const int &b)
{
a = a+1;
b = b*b;
return a+b;
}
我认为编译器不会允许你这样做,因为你试图显式地修改通过const
保护的值。
另一个需要使用const
的重要时刻是当你通过指针传递参数而不是引用或副本时...
int funcB(int *a, int *b)
{
a = a+1;
b = b*b;
return a+b;
}
除非你是指针专家,否则避免在没有const修饰的情况下传递指针。这个函数可能会尝试迭代指针数组的索引,从而导致与内存越界相关的运行时错误。你可能会意外地看到来自完全不同程序的内存...但很可能不会。
最后,由于你只是传递int
,没有实际需要通过引用传递(通常这样做是为了避免将复杂数据添加到内存中,因为每个非引用或非指针传递到函数中都会将值复制到被调用函数的内存中),因为int
的内存占用非常小。除非你正在使用具有极限内存的专用硬件,否则它可能有用;这不适用于大多数标准计算机、桌面电脑和智能手机,这些设备在过去20年内制造。
如果你想真正地实现const正确性,那么你应该添加它,但实际上它只会让你输入和阅读更多。
没有任何东西会变得更快,虽然它可能意味着你的变量会进入内存中的另一个位置,但在大多数现代机器上这是不太可能的。
它将阻止你意外地给它们赋值,但由于它们是函数局部变量,所以相对不重要。如果它们是引用,那么这就说明了你向调用者表明不要更改它们的意图,这才是最重要的。
如果你喜欢的话,可以在那里使用const
。
这不太可能加速你的程序,因为任何合理的编译器都可以看到没有代码路径会改变a
或b
的值,并进行任何所需的优化。
a
和b
是int
类型,它们是按值传递的,因此将它们设置为const
对该函数的用户没有影响。
唯一可能的好处是当你的函数很长且更复杂时,你想避免可能的编程错误,即在函数期间更改a
或b
的原始值。
bool SomeFunction (const myObj& obj);
作为惯例,我们被建议尽可能使用const,因为我们可以从编译器获得很大的帮助,因此每当我们尝试更改常量时,编译器都会捕捉到错误;这是一件好事,可以避免被错误包围。
第二件事:a和b以值传递,因此它们被创建为本地常量,但只要它们不可改变,为什么我们需要副本?
好处是传递一个常量引用,这意味着永远不会更改参数并避免副本(按值复制):int add(const int a, const int b)
{
return a+b;
}
在这里使用const,以确保函数不会无意中修改a和b的原始值。 在上面的示例中,这样做没有意义。但如果它是像下面这个例子:
int add(const int *a, const int *b)
{
//*a = 10; //This will throw error.
return a+b;
}
const引用
而不仅仅是const是一个好的方法。 - Markus Kull
const
会让人感到困惑(void foo(int)
和void foo(const int);
完全相同)。但在定义中不是这样的。当然,这只是我的观点(因此是评论,而不是答案)。 - juanchopanzaconst
值传递有助于衡量程序员的能力:我有时发现这很有用。 - Bathsheba