慎用const_cast

转自:http://blog.solrex.cn/articles/%E6%85%8E%E7%94%A8const_cast.html

Program:
#include <iostream>

using namespace std;

int main()
{
const int a = 1;
int *p = const_cast<int*>(&a);
*p = 2;
cout << “value a=” << a << endl;
cout << “value *p=” << *p << endl;
cout << “address a=” << &a << endl;
cout << “address p=” << p << endl;
return 0;
}

这个程序,从语法上看,没有任何问题(当然,这种用法不提倡 deprecated )。但是输出结果却是这样的:

value a=1
value *p=2
address a=0xbfe9efb4
address p=0xbfe9efb4(depends on machine)

奇怪了,a和p既然指向同一块地址,为什么输出的内容却不一样呢?

在调试的时候发现,在运行完*p=2时,调试器打出的a的地址和p是一样的,而且a和*p的内容都是2。但为什么输出时候会a=1呢?

还是看汇编代码吧,相关部分:
subl $8, %esp
pushl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
subl $12, %esp
//将直接数1压栈
pushl $1
//栈顶指针减12
subl $12, %esp
pushl $.LC0
pushl $_ZSt4cout
.LCFI7:
//这句是”value a=”这个字符串的输出函数,char
call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
//栈顶指针增加20
addl $20, %esp
pushl %eax
//这句是a的值输出,int
call _ZNSolsEi
addl $20, %esp
pushl %eax
.LCFI8:
//这句是输出的endl
call _ZNSolsEPFRSoS_E
addl $16, %esp

看完之后,有人会问了:怎么没看到a在哪里输出的啊,那么请你注意上面“栈顶指针增加20”这个注释,增加20之后它到哪里了?注意上面就会发现,前面有两次压栈,指针减4*2=8,一次指针减12,然后再加上20,这时候栈顶指针就到了“将直接数1压栈”下面了,显然进入输出函数后,它会从栈中找输出某个值,这里显然是数字1。

这就是为什么会输出a=1了,因为编译器根本没去找a的值,因为a是const int型,编译器认为它的内容不会变,所以干吗非得去内存中找啊,多麻烦,直接把值放到code里输出不就行了!

从某种意义上来说,const 相当于宏定义,但是程序为变量分配了存储空间,这样就可以进行类型检查。所以说很多 C++ 书籍作者提倡用 const 来代替 define,而且反对对 const 做 cast。就算要做 cast,也请尽量使用 C++ 的 cast 而不是 C 的类型转换。

恶劣的编程风格会带来不可预测的后果。类型转换之类的C留下来的习惯在编写高效率的程序时候是很有用的,但一定要确保知道采用这种方式会产生什么结果再去使用。对于那些 undefined 和 deprecated 的东西可以去利用,但是脑子中一定要有 idea。

posted @ 2009-05-21 17:17  莫小  阅读(1594)  评论(1编辑  收藏  举报