本文为简单读后感/翻译/粗浅理解
cv-qualifier实际上是 cv (const and volatile) type qualifiers的缩写。
1 什么变量是const 的?
如果一个变量:
- 被
const修饰;或 - 是一个
const对象的non-mutable成员
那么它就是const的。
一个const的变量在代码里不能直接的修改它,否则会编译错误。但是我们依然可以隐式地修改它,比如用指针去修改它之类的。这样的操作是未定义的,因为编译器会对const做一系列优化,修改了它之后谁也不知道会发生什么事情。
2 什么变量是volatile的?
如果一个变量:
- 被
volatile修饰;或 - 是一个
volatile对象的成员;或 - 是一个
const-volatile对象的mutable成员
那么它就是volatile的。
每次对它的访问(包括读、写、调用成员函数等)都会被视为一个visable side-effect,编译器会保证它和发生在它之前或之后的visable side-effect依然保持原来的顺序。也就是说编译器不会随便对它做优化,因为人告诉编译器这个变量可能会发生编译器无法预知的变化。
比如在下面这段代码里,显然变量a是不会变化的,这样的话编译器(gcc 11.2 -O2)就会把while循环给优化成一个条件永真的死循环:

然而如果我们声明变量a是volatile的,那么每次while循环的时候都会去访问一下a然后和 10 做一下比较:
这个看起来和 memory_order 有点类似,但并不是一种东西。volatile只是对一个thread里的操作进行约束,多线程之间并没有保证。
3 什么变量是const volatile的?
一般来说很难见到const volatile的变量,它们是:
an object whose type is const-volatile-qualified, a non-mutable subobject of a const volatile object, a const subobject of a volatile object, or a non-mutable volatile subobject of a const object.
它既有`volatile`的性质,也有`const`的性质。也就是说我们不让程序修改这个值,但是我们又告诉编译器有可能别的地方会有人修改这个值。那么它有什么用呢?<br />下面这个回答告诉我们:在嵌入式里,他们经常见到这样的写法。这是因为很多时候会遇到这样一种变量,它们和硬件端口绑定,所以随时可能会被硬件修改;然而我们的程序不应该去修改这个值。这种情况显然符合`const volatile`的场景。比如你想读取`ALU`的`ready`位以确定当前的运算是不是结束了,那么这个值显然是当前程序不应该修改也不能修改的,而且它还随时可以被别的人(硬件)修改。
4 什么是mutable修饰符?
有些时候我们希望一个函数被声明为const的,但是又不得不在这个函数里面对一个变量进行修改,此时我们就可以声明这个变量为mutable的。
当然,我们很自然地会产生一个问题,既然你想修改变量,那就不要把自己声明成const就好了。这的确是一种解决方案,但是有可能整个函数都非常的const仅仅是那么一个变量破坏了这个规矩,或者是这个函数从语义上来说就非常const,仅仅因为那个小变量就放弃了可能的编译器优化,不是非常值当。
这里有一个 best practice 叫做:M & M rule,它是指:我们应该把类里的 mutex 成员声明为mutable。这里是想解决这样一个问题:我们很多时候希望这个类是线程安全的,所以当我们读取一个成员变量的时候调用getXXX()函数需要在函数里加锁。这里可能会用到类里的那个 mutex 成员变量,而且加锁会改变这个 mutex,显然这个函数就不能是const的;然而我们知道一个getXXX函数(类似于一个 getter )从道理上来说就应该是const的。这里就可以把这个 mutex 变量声明成为一个mutable变量。
5 转化优先级
不知道应该怎么翻译这一段内容,直接复制上来了:
There is partial ordering of cv-qualifiers by the order of increasing restrictions. The type can be said more or less cv-qualified than:
- unqualified < const
- unqualified < volatile
- unqualified < const volatile
- const < const volatile
- volatile < const volatile
References and pointers to cv-qualified types may be implicitly converted to references and pointers to more cv-qualified types.
它告诉我们一个没有 cv 修饰符的变量可以被转化为 const、volatile 或 const volatile 的引用。这也是我们写代码的时候经常这样写的依据:
void foo (const int &a) {std::cout << a << std::endl;}int a = 100;foo(a);foo(10);
