我知道const
在函数参数上使用关键字可以提供更好的性能,但我总是忘记添加它。编译器(在这种情况下为 GCC)是否足够聪明,可以注意到变量在函数期间永远不会改变,并像我const
显式添加一样编译它?
5 回答
你对const
. 只创建一个对象 const
意味着它的值永远不会改变,然后它不仅仅是在函数期间,它永远不会改变。
给函数设置参数const
并不意味着它的值永远不会改变,它只是意味着函数不能通过那个const
指针改变值。该值可以以其他方式改变。
例如,看这个函数:
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
指针,但它指向一个非常量对象。所以值可以改变,因为它是指向同一个对象y
的非const
指针。所有这些都是完全合法的代码。这里没有有趣的事情。
因此,您的问题实际上没有答案,因为它完全基于错误的前提。
编译器(在这种情况下为 GCC)是否足够聪明,可以注意到变量在函数期间永远不会改变,并像我会显式添加 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
不可用的优化。
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
。因此,是否标记为 const 应该没有区别,a
因为编译器知道它无论如何都不会改变。
当然,调试器支持会使这种情况复杂化——我不知道gcc
和的情况如何gdb
,但至少在理论上,如果编译器想要支持你使用调试器并a
手动修改,那么它可能不会将其视为不可修改. 这同样适用于some_function
使用特定于平台的功能爬上堆栈并弄乱a
. 平台不必提供此类功能,但如果提供,则与优化冲突。
我见过旧版本的 gcc(3.x,不记得 x)未能进行某些优化,而我未能创建局部int
变量const
,但在我的情况下,gcc 4 确实进行了优化。无论如何,我想到的情况不是参数,它是一个用常量值初始化的自动变量。
a
在我所说的任何内容中,作为参数都没有什么特别之处——它也可以是函数中定义的任何自动变量。请注意,使用常量值获得初始化效果的参数的唯一方法是使用常量值调用函数,并让编译器观察该调用的值。这往往只在函数被内联时发生。因此,对函数的内联调用可以对它们应用额外的优化,而“out-of-line”函数体不符合条件。
const与inline非常相似,只是对编译器的提示,并不保证任何性能提升。const更重要的任务是保护程序员免受他们自己的伤害,这样他们就不会不愿意在不应该修改的地方修改变量。
1)真的 const不会直接影响你的表现。在某些情况下,它可能会进行更简单的指向分析(因此更喜欢const char*
)char*
,但 const 更多的是关于代码的语义和可读性。
2) CV 限定类型在 C 和 C++ 中形成不同的类型。所以你的编译器,即使它从默认的 const 中获益,也不会这样做,因为它会改变类型并可能导致令人惊讶的奇怪事情。
作为优化的一部分,编译器正在深入研究何时读取或写入内存位置。因此编译器非常擅长检测变量何时未更改(const)以及何时更改。当变量为 const 时,优化器不需要你告诉他。
尽管如此,您应该始终在适当的时候使用 const。为什么?因为它使界面更清晰,更容易理解。当您更改不想更改的变量时,它有助于检测错误。