const_cast去除const限制,同一片内存
本质很简单,但一些优化 和 编程上的错误,却让人看不清本质。
:const_cast<type_id> (expression)
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
一、常量指针被转化成非常量的指针,并且仍然指向原来的对象;
二、常量引用被转换成非常量的引用,并且仍然指向原来的对象;
就是说,转换之后仍是原来的内存,只是变量的属性变了,看待该内存的方式变了。
下面解释一下,一些让人看不清本质的情况
1.编译器的优化
const int a = 10; cout<<a<<endl; //10 //a = 20; //编译出错 const_cast<int&>(a) = 20; //转化成引用 cout<<"a: "<<a <<endl; //a的结果依然是10,a的内容没有变化?
可以看到a的值没有变化,依然是10。为什么呢?难道是新的内存,修改的是临时值? 但引用应该只是别名。
转换成指针看看地址
//int * p = &a; //编译出错 int * p = const_cast<int*>(&a); *p = 20; cout<<"a: "<<a << " a address:"<< &a <<endl; //10 cout<<"*p:"<<*p<<" p content:" <<p<< " p address: "<<&p<<endl; //20 //但p指向的是a的地址,两个内容应该 一致,所以是由于编译器的优化。
看到a的值没变,但*p变化了。而&a 与p 的内容一样,即p就是指向a的,两个是同一片内存,但打印出来的内容不一致,考虑由于编译器优化的原因。
volatile const int b=11; cout<<"b:"<<b<<endl; const_cast<int&>(b) = 22; cout<<"b: "<<b << " b address:"<< &b <<endl; //22好了,引出新问题,为什么地址为1 printf("printf:%p\n",&b); //可以打印出地址
好了,加上volatile之后,不让编译器优化,每次都去内存中取值就正确了。
所以const_cast转化成引用或指针后,扔指向的是原来的内存,可以修改内存中的数据。
注:这里有一个新的发现,打印&b, b的地址的时候,用cout打印出1,printf打印出地址。这是为什么呢?仍是编译器的优化吗?
2.一些错误导致本质不清。
volatile const int b=11; int bk = const_cast<int&>(b); bk = 22; cout<<"b: "<<b << " bk: "<< bk <<endl; // b: 11 bk:22
仔细看,可以知道,修改的是变量bk的值,并没有修改b所只内存的值。虽然是引用,但bk没有申明为引用,是个新的变量。
可能本意是 int& bk = const_cast<int&>(b);
因此,很多错误,导致原本看清的本质变得模糊,甚至开始怀疑。
在测试的时候,必须保证你的代码是你原本想要的样子,才能继续测试你怀疑的真相!
路是一步一步走的