const语义
参考:
1. const 限定了什么
const 实际上有两层意思:
- 物理上的 constness
- 逻辑上的 constness
1.1 物理上的 constness
例如:
const int a = 1;
const char* b = "hello, world";
c 语言中的字面量:char* c = "...";
等等...
这些常量在编译的时候被放入了 .rodata 段,如果用户代码强制修改一个物理上的常量,编译器会直接报错:
const int a = 1;
const int* b = &a;
*b = 3;
可以利用 const_cast 跳过编译器的报错:
const int a = 1;
int* b = const_cast<int*>(&a);
*b = 3;
但是,修改一个只读区域的数据,结果将是未定义的、危险的行为。
1.2 逻辑上的 constness
例如:
const Test obj;
void func(const T* a) {}
等等...
实际上我们能否正确的改动逻辑上的 const 常量,取决于它们的背后是不是物理上的常量,如果是,那么就是 1.1 节定义的,如果不是,可以通过 const_cast 消除常量性。
例如:
对于:
void func(const T* a) {}
如果调用为:
Test obj;
func(&obj);
那么,在 func 内部通过 const_cast 去除常量性再操作 Test 对象是安全的
如果调用为:
const Test obj;
func(&obj);
那么,在 func 内部通过 const_cast 去除常量性再操作 Test 对象结果是未定义的
1.3 const 类对象
const 类对象只能调用 const 成员函数,只能读不能写成员变量。但是,如果一个成员如果被声明为了 mutable 类型,那么这个变量便能打破规则,在 const 成员函数中能够被改动。
2. 总结
程序员 A 写下了一个函数接口,函数有一个 const T* a 类型的形参,程序员 A 的本意是希望其它程序员不要修改变量 a 指向的对象,如果有修改的代码,编译器会帮助提醒报错。但是,其它程序员依然可以通过 const_cast 转型为非 const 类型,如果这样做,其它程序员必须知道实参是什么。