当对象最初被创建时,所用的 cv 限定符(可以是声明中的 声明说明符序列 或 声明符 的一部分,或者是 new 表达式中的 类型标识 的一部分)决定对象的常量性或易变性。
const限定符
const用来修饰一个常量,该常量不可以被修改。如果通过其他方式(通过到非 const 类型的引用或指针修改 const 对象),其结果是未定义的。
主要关心以下几点:
1、const对象的内存分配
命名空间作用域定义的const对象,其默认具有内部链接性。当在头文件里定义const对象的时候,即使该头文件被多个源文件包含也不会出现变量的重定义。这就涉及到编译器对常量的处理:
C++编译器都会尽量避免const 常量的内存分配,只有当不得已的时候才会分配具体的内存空间给const变量。如使用extern修饰一个常量,由于其需要在不同翻译单元之间共享,必须有地址。或者是在运行期间创建的常量,如在函数中创建一个常量,编译器是没有办法提前知道它的值的,因此也是分配了内存,只不过把这段内存设为只读。
这也就是为什么默认的const对象拥有内部链接性,即使分配了内存地址,也不会造成其他翻译单元尝试去链接。
2、指针的顶层const和底层const
- const int * a ---> const + int * a : a是一个指针,其指向的东西(*a)是const修饰的,无法被修改。
- int const *a 同上,const修饰 *a
- int * const a ----> int* + const a : a是一个被const修饰的指针,指针本身的值无法被修改
- const int * const a -----> a是一个const修饰的指针,其指向的东西也是被const修饰的
3、const成员函数
标记该成员函数不会对成员变量进行修改
volatile限定符
主要是对编译器的优化做提示,编译器会对一些多次访问的值之间放到寄存器里。但多线程环境下可能会出现不一致的情况。
使用该限定符就是告诉编译器不对该变量进行寄存器优化,每次都必须从内存里取值。
mutable 说明符
<strong>mutable</strong>
- 容许在即便包含它的对象被声明为 const 时仍可修改声明为 mutable 的类成员。
只用于对类的成员进行标记,一般用于类的线程同步相关成员(互斥体、记忆缓存、惰性求值和访问指令):
class ThreadsafeCounter {
mutable std::mutex m; // “M&M 规则”:mutable 与 mutex 一起出现
int data = 0;
public:
int get() const {
std::lock_guard<std::mutex> lk(m);
return data;
}
void inc() {
std::lock_guard<std::mutex> lk(m);
++data;
}
};
这样即使声明了一个const对象,也能在调用get()的时候正常加锁。
叨叨几句... NOTHING