cv(const 与 volatile)类型限定符

发布于 2021-09-18  45 次阅读


当对象最初被创建时,所用的 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()的时候正常加锁。


当其他人都认为你要鸽的时候,你鸽了,亦是一种不鸽