我知道在函数参数上使用const
关键字可以提供更好的性能,但我总是忘记添加它。编译器(在这种情况下是GCC)是否足够聪明,可以注意到变量在函数期间永远不会发生变化,并将其编译为好像我会明确添加const
一样?
答案 0 :(得分:4)
您对const
有一个共同的误解。只创建一个对象 const
意味着它的值永远不会改变,然后它不仅仅是在一个函数中,它永远不会更改。
为函数const
创建一个参数 not 意味着它的值永远不会改变,它只是意味着函数不能改变值through that const
pointer。价值可以改变其他方式。
例如,看看这个函数:
void f(const int* x, int* y)
{
cout << "x = " << *x << endl;
*y = 5;
cout << "x = " << *x << endl;
}
请注意,它需要const
指向x
的指针。但是,如果你这样称呼它:
int x = 10;
f(&x, &x);
现在,f
有一个const
指针,但它是一个非const对象。因此值可以更改,因为y
是指向相同对象的非const
指针。所有这些都是完全合法的代码。这里没有好玩的事。
所以你的问题真的没有答案,因为它完全基于错误的前提。
答案 1 :(得分:3)
编译器(在这种情况下是GCC)是否足够聪明,可以注意到 varbele在函数期间永远不会改变,并像我一样编译它 会明确添加const吗?
不一定。例如:
void some_function(int *ptr); // defined in another translation unit
int foo(int a) {
some_function(&a);
return a + 1;
}
编译器无法看到some_function
的作用,因此不能认为它不会修改a
。
链接时优化可能会看到some_function
真正做了什么并采取相应的行动,但就这个答案而言,我只会考虑some_function
的定义不可用的优化。 / p>
int bar(const int a) {
some_function((int*)&a);
return a + 1;
}
编译器无法看到some_function
的作用,但可以假设a
的值无论如何都不会改变。因此,它可以进行任何适用的优化:也许它可以在a
的调用中将some_function
保留在被调用者保存寄存器中;也许它在进行调用之前计算返回值而不是之后,并且zaps a
。如果some_function
修改a
,则程序具有未定义的行为,因此一旦发生这种情况,编译器的POV就会对a
使用“正确”或“错误”值无关紧要
因此,在此示例中,通过标记a
const,您告诉编译器它无法知道的事情 - some_function
不会修改*ptr
。或者无论如何,如果它确实修改了它,那么你不关心程序的行为是什么。
int baz(int a) {
some_function(NULL);
return a + 1;
}
在这里,编译器可以看到与标准相关的所有相关代码 。它不知道some_function
做了什么,但它确实知道它没有任何标准方法来访问a
。因此,a
是否标记为const应该没有区别,因为编译器知道它不会改变。
调试器支持可能会使这种情况复杂化 - 当然 - 我不知道gcc
和gdb
的情况如何,但理论上至少如果编译器想要支持你打破调试器并手动修改a
然后它可能不会将其视为不可修改。这同样适用于some_function
使用特定于平台的功能来使用堆栈并混淆a
的可能性。平台不 提供此类功能,但如果他们这样做,则会与优化冲突。
我见过一个旧版本的gcc(3.x,不能记住x)未能在我未能制作本地int
变量const
的情况下进行某些优化,但是我的情况gcc 4确实进行了优化。无论如何,我想到的情况不是参数,它是一个用常量值初始化的自动变量。
a
在我所说的任何一个参数中没有什么特别的 - 它也可以是函数中定义的任何自动变量。请注意,使用常量值获取初始化效果的参数的唯一方法是使用常量值调用函数,并使编译器观察该调用的值 。只有在函数内联时才会发生这种情况。因此,对函数的内联调用可以对其应用额外的优化,即“外联”函数体不符合条件。
答案 2 :(得分:2)
const ,与 inline 非常相似,只是编译器的提示,并不保证任何性能提升。 const 更重要的任务是保护程序员免受他们自己的影响,这样他们就不会在不应修改变量的情况下修改变量。
答案 3 :(得分:1)
1)真正的const 不会直接影响您的表现。在某些情况下,它可能会使分析更简单(因此更喜欢const char*
到char*
),但const更多地是关于代码的语义和可读性。
2)CV-qualified类型在C和C ++中形成不同的类型。所以你的编译器,即使看到制作默认const的利润,也不会这样做,因为它会改变类型并可能导致令人惊讶的奇怪事情。
答案 4 :(得分:0)
作为优化的一部分,编译器正在深入研究何时读取或写入内存位置。因此,编译器非常擅长检测变量何时未更改(const)以及何时更改。当变量是const时,优化器不需要你告诉他。
尽管如此,你应该在适当的时候使用const。为什么?因为它使界面更清晰,更容易理解。当你更改一个你不想改变的变量时,它有助于检测错误。