昨天看Bruce Eckel的Thinking in C++,上面谈到了const folding的问题,大家对中文版把该术语翻译成“常量折叠”意见挺大的,先不管怎么翻,内在意思就是编译器在编译时可以通过必要的计算把一个复杂的常量表达式通过缩减简单化。开始时觉得不大明白,接着又搜出下面一段比较有代表性的代码:
开始看过这段程序的感觉就有个疑问:这样编译能够通过么?非常出乎意料,程序不但编译通过,而且输出结果是3。那么为什么在指针p对存储内容进行修改以后a的值还是3呢?直观上感觉结果应该是4。个人理解,程序在执行const int a = 3;这句后并没有为a分配存储空间,但在符号表里新建了一条表项用于保存a的记录,常量折叠使得编译器把以后程序段中出现的所有标识符a都用3代替,于是输出结果就是3了。但*p = 4又作何解释呢?int* p = const_cast(&a);使得编译器为常量a分配存储空间(定义a为常量时没有分配),这样才可能进行取地址操作,*p = 4对该空间的a值进行了修改,但并没有影响符号表中常量a的值,这估计就是原因所在了。
这又引出了C++中怎样为const分配存储空间的问题。根据Bruce Eckel的理论,“在C++中,是否为const常量创建内存空间依赖于对它如何使用。一般说来,如果一个const仅仅用来把一个名字用一个值代替(如同使用#define一样),那么该存储空间不必创建。不过,如果取一个const的地址(甚至不知不觉地把它传递给一个带引用参数的函数)或者把它定义成extern,则会为该const创建内存空间。”,这段话可以辅助说明上面那段程序例子的运行结果。因为对a取地址了,编译器就为const a分配了存储空间。