const_cast
C++的四种类型转换关键字之一, const_cast , static_cast , dynamic_cast, reinterpret_cast 。
不可以去除一个 const 变量的 const 属性。可以跨过 const 访问原始变量( 和 const 变量不同 )。
很容易理解错的一个例子:
#include <bits/stdc++.h>
using namespace std ;
int main () {
const int data = 100 ;
int *p = const_cast<int*>( &data ) ;
cout << "data = " << data << "\t地址 : " << &data << endl << endl ;
cout << " p = " << *p << "\t地址 : " << p << endl << endl ;
*p = 200 ;
cout << "data = " << data << "\t地址 : " << &data << endl << endl ;
cout << " p = " << *p << "\t地址 : " << p << endl << endl ;
cout << "实际内存中的内容 : " << *(int*)(0x6ffe34) << endl << endl ;
return 0 ;
}
实际运行结果, 编译器 g++ , 支持 C++14
很奇怪? data 的地址是 0x6ffe34, p 指向的地址也是 0x6ffe34, 但是修改 p 之后, 同一个地址上的内容却不相同。
可能是 const 的问题? const 的机制,就是在编译期间,用一个常量代替了 data。
关键在这里:
#include <bits/stdc++.h>
using namespace std ;
int main () {
const int volatile data = 100 ;
int *p = const_cast<int*>( &data ) ;
cout << "data = " << data << "\t地址 : " << &data << endl << endl ;
cout << " p = " << *p << "\t地址 : " << p << endl << endl ;
*p = 200 ;
cout << "data = " << data << "\t地址 : " << &data << endl << endl ;
cout << " p = " << *p << "\t地址 : " << p << endl << endl ;
cout << "实际内存中的内容 : " << *(int*)(0x6ffe34) << endl << endl ;
return 0 ;
}
运行结果正常, data 地址和 p 指向的地址一致,内容也是一致的,都是修改后的 200 。
可以注意到,程序的差别就在一个 volatile , volatile 的作用是取消编译器的优化,每一次使用该内存信息,都很小心地重新读取这块内存的内容。如果没有 volatile, 编译器会采取一些优化,例如把 const 变量拷贝一份放在寄存器中( 或者类似于 cache,这样速率就高 ), 没有 volatile 就意味着,程序一直调用的 const data 都是一份拷贝,不仅含有该 const 变量的地址,,还含有该 const 变量的信息,不允许修改,但,不是真正的那个内存。真正的内存信息通过 const_cast 改变了,但是一般无法获取到该内存的信息( 因为首先是考虑寄存器中的那份拷贝 )。
volatile 就可以重新,稳定地读取该 const 常量真正内存的信息,如果被改变了,也可以得到内存信息。
第一个程序的 data 不是 const 常量的真正内存,只是一份在寄存器的拷贝, 不允许改变的拷贝。但是,缺点就是如果 const 变量经过一些方式被改变了,寄存器中的拷贝就会有 “延迟” 。
第二个程序, 在 volatile 的作用下,每次要使用 data 时都需要重新读取原地址,一直都是原始的那份内存,优点是不会有延迟,较为安全(尤其是在多线程的环境下)。所以,通过 const_cast 改变的内存可以及时反映。
但是 const_cast 并没有改变 const 变量的 const 属性,改变的只是原始声明 const int data = 100 中,data 地址指向的内存。 const 属性和 data 都被翻译成机器的代码了,可执行程序是不可变的,其中的 const data 是已经确定了的,的确存在于寄存器中,和原来的内存没有关系了 。等到学了反汇编,也许就更清楚了。