sla*_*ast 76 c c++ pointers const const-correctness
我知道它提高了可读性并使程序不易出错,但它提高了多少性能?
在旁注中,参考和const
指针之间的主要区别是什么?我会假设它们以不同的方式存储在内存中,但是如何呢?
Nem*_*emo 69
[编辑:好的,所以这个问题比起初想的更微妙.]
声明指向const或const-reference的指针永远不会帮助任何编译器优化任何东西.(虽然请参阅本答案底部的更新.)
的const
声明仅指示如何的标识符将内使用范围其声明的; 它并没有说底层对象无法改变.
例:
int foo(const int *p) {
int x = *p;
bar(x);
x = *p;
return x;
}
Run Code Online (Sandbox Code Playgroud)
编译器不能假设*p
调用没有修改bar()
,因为p
可能是(例如)指向全局int的指针并bar()
可能修改它.
如果编译器对调用者foo()
及其bar()
可以证明bar()
不会修改的内容有足够的了解*p
,那么它也可以在没有const声明的情况下执行该证明.
但总的来说这是事实.因为const
只在声明范围内有效,编译器才能看到你如何处理该范围内的指针或引用; 它已经知道你没有修改底层对象.
简而言之,const
在这种情况下所做的一切都是为了防止你犯错误.它没有告诉编译器任何它不知道的东西,因此它与优化无关.
那叫的功能怎么样foo()
?喜欢:
int x = 37;
foo(&x);
printf("%d\n", x);
Run Code Online (Sandbox Code Playgroud)
可以编译器证明这打印37,因为foo()
需要一个const int *
?
foo()
不会.即使采用指向const的指针,它也可能会抛弃const-ness并修改int.(这不是未定义的行为.)同样,编译器一般不能做任何假设; 如果它知道足够foo()
进行这样的优化,它就会知道即使没有const
.
唯一const
可能允许优化的时间是这样的情况:
const int x = 37;
foo(&x);
printf("%d\n", x);
Run Code Online (Sandbox Code Playgroud)
在这里,x
通过任何机制进行修改(例如,通过获取指针并抛弃它const
)是调用Undefined Behavior.因此,编译器可以自由地假设您不这样做,并且它可以将常量37传播到printf()中.这种优化对于您声明的任何对象都是合法的const
.(实际上,您从未参考过的局部变量不会受益,因为编译器已经可以看到您是否在其范围内修改它.)
要回答你的"旁注"问题,(a)const指针是一个指针; (b)const指针可以等于NULL.你是正确的,内部表示(即地址)很可能是相同的.
[更新]
正如Christoph在评论中指出的那样,我的答案是不完整的,因为它没有提及restrict
.
C99标准的第6.7.3.1(4)节说:
在每次执行B期间,让L为具有基于P的&L的任何左值.如果L用于访问它指定的对象X的值,并且X也被修改(通过任何方式),则以下要求适用:T不应该是const限定的....
(这里B是一个基本块,P是一个限制指针到T的范围.)
所以如果C函数foo()
声明如下:
foo(const int * restrict p)
Run Code Online (Sandbox Code Playgroud)
...然后编译器可以假设*p
在生命周期内没有发生修改p
- 即,在执行期间foo()
- 因为否则行为将是未定义的.
因此,原则上,restrict
与指向const的指针结合可以实现上面所述的两种优化.我想知道,任何编译器都会实现这样的优化吗?(GCC 4.5.2,至少没有.)
请注意restrict
,除了作为特定于编译器的扩展之外,仅存在于C中,而不是C++(甚至不是C++ 0x).
const
C++中有两个问题(就优化而言):
const_cast
mutable
const_cast
意味着即使你通过const引用或const指针传递一个对象,该函数也可能会抛出const-ness并修改对象(如果对象不是const开头,则允许).
mutable
意味着即使一个对象是const
,它的一些部分可能被修改(缓存行为).此外,指向(而不是拥有)的对象可以在const
方法中进行修改,即使它们在逻辑上是对象状态的一部分.最后全局变量也可以修改......
const
是为了帮助开发人员尽早发现逻辑错误.
在我的脑海中,我可以想到两种情况,其中适当的const
资格允许额外的优化(在整个程序分析不可用的情况下):
const int foo = 42;
bar(&foo);
printf("%i", foo);
Run Code Online (Sandbox Code Playgroud)
在这里,编译器知道打印42
而不必检查bar()
(在curent翻译单元中可能不可见)的主体,因为所有修改foo
都是非法的(这与Nemo的例子相同).
但是,这也有可能无标记foo
的const
通过声明bar()
为
extern void bar(const int *restrict p);
Run Code Online (Sandbox Code Playgroud)
在许多情况下,程序员实际上需要restrict
- 指定指针const
而不是普通指针const
作为函数参数,因为只有前者才能保证指向对象的可变性.
关于你问题的第二部分:出于所有实际目的,可以将C++引用视为具有自动间接的常量指针(不是指向常量值的指针!) - 它不是任何"更安全"或"更快"的比一个指针,只是更方便.
归档时间: |
|
查看次数: |
7302 次 |
最近记录: |