%%
# 纲要
> 主干纲要、Hint/线索/路标
# Q&A
#### 已明确
#### 待明确
> 当下仍存有的疑惑
**❓<font color="#c0504d"> 有什么问题?</font>**
%%
# CV 限定符
> cv 限定符 (cv type qualifiers)
cv 限定符是描述变量或对象的**类型说明符**(type specifier),用于指定"**被声明的对象**"或"**被命名的类型**"的 **==常量性==**(constness)或 **==易变性==**(volatility),其指示编译器关于对象如何被访问和修改的信息,**会影响编译器的优化策略**。
"**cv-qualified**" 类型即指带有 `const` 或 `volatile` 或 `const volatile` 修饰符的类型。
C++中,除"**引用**"和"**函数**"类型以外,其余**任何类型**都属于下列四种情形之一:
> 
<br><br>
# `const` 修饰符
**const 限定符可以用于任何数据类型**,标识 **==对象的值不能被修改==**,即**声明为一个==常量==**。
一旦一个对象被声明为 `const`,就不能再被赋予新的值。
> [!NOTE] const 修饰一个 `non-extern` &`non-local` &`non-volatile` & `non-template` & `non-inline` 变量时,将指定 "**==内部链接性==**"。
<br>
## 顶层/底层 const
根据 `const` 修饰/影响的是 "**==对象本身==**" 还是其 "**==所指向的内容==**",可以将 `const` 修饰分为两种[^2](P58):
- **==顶层 const==**(top-level const):修饰**变量本身**的 `const`,适用于任何数据类型。
- **==底层 const==**(low-level const):修饰**变量所指向/引用对象**的 `const`,与指针、引用有关。
区分 "值类型"、"引用类型"、"指针类型" 三种情况:
- 对于==**值类型**==(非指针非引用类型),**只存在 "==顶层== `const`"** ,即**修饰==对象本身==的 `const`**。
- 对于==**引用类型**==来说,**只存在"==底层== `const`"** ,**修饰==引用的对象==而不是引用本身**。
- 对于==**指针类型**==来说:
- "**顶层 `const`**" 表示**指针本身是个常量**(Const Pointer)
- "**底层 `const`**" 表示**指针所指向的对象是常量**(A Pointer to A Const)
- **"底层 `const`" 本身==属于指针类型的一部分==,因此不能被忽略**。
- 对一个常量对象 "**取地址**`&`",得到"**指向常量的指针**"类型,是一种"底层 `const`"
> [!example] 说明示例
>
> ```cpp
> const int // 顶层 const
> const int& // 底层 const
> const int* // 底层 const, 指向常量的指针(pointer to const), 不能通过指针"修改所指对象的值".
> int* const // 顶层 const, 常量指针(const pointer), 指针本身的值不可改.
> const int* & // 修饰"指针"的底层 const, 不能通过引用修改"指针所指对象的值", 但可更改"指针本身的值".
> int* const & // 修饰"引用"的底层 const, 对"常量指针"的引用, 不能通过引用修改"指针的值", 即指针指向不可变;
> const int* const & // 第二个const对于指针而言是 "顶层const", 同时也是引用的 "底层const"。 两个const表明, 该引用所绑定的指针, 指针本身值不可改, 指针所指对象的值也不可改.
> ```
>
```cpp title:const_level_of_pointer.cpp
int a = 5;
int* const ptr = &a; // 顶层 const, 常量指针, 指针所指向的地址不可改
const int* ptr2 = &a; // 底层 const, 指针指向一个 `const int` 对象, 不可通过该指针修改被指对象的内容
```
### 使用说明
> [!info] 参见 [^1] (Item 1) [^2] (P191)
>
> (1)**为常量对象==绑定引用==,或者==取址赋给指针==时**,**==常量对象的顶层 const 属性将会保留==**:
>
> - "常量对象"只能由常量引用来绑定。
> - 对"常量对象"取址 `&` 得到指向"常量类型"的指针,因此只能赋给 "指向常量类型" 的指针。
>
> ```cpp title:const_obj_to_ref_or_pointer.cpp
> const int i = 5;
> // int *p = &i; // error: 对常量取址&得到的是指向"常量"的指针类型, 不能赋值给指向非常量的指针
> const int *cp = &i;
> // int& ref = i; // error: 常量对象只能由常量引用绑定
> const int& cref = i;
> ```
>
> (2)在 **"值传递/拷贝"** 场景下,**==顶层== `const` 都会被忽略**,例如 **==赋值==** 、**==函数参数的"值传递"==** 等。<br> 此外,**在 `auto`、`typeid` 对值类型的推导中也会忽略顶层 `const`**,而在 `decltype` 中不会。
>
> - "常量指针" 可以用于初始化 or 赋值给 "非常量指针",只要二者的指针类型相同(底层 `const` 属于指针类型的一部分)
> - "常量对象" 可以赋值给同类型的 "非常量"对象。
>
> ```cpp title:top-level-const
> int i = 1;
> const int cn = 5;
> int* const pc = &i;
> const int* const cpc = &i;
>
> // "顶层 const"属性在值传递过程中始终忽略.
> int *p3 = pc; // 忽略pc的顶层`const`
> const int *cp3 = cpc; // 忽略cpc的顶层`const`
> int n = cn; // 忽略cn的顶层`const`
> ```
>
>
> (3)**指针和引用**的"**==底层== `const`**" 属性**不允许在值传递/拷贝过程中丢失, 但可以增加**。
>
> - "指向常量的指针" 不能用于初始化 or 赋值给一个 "指向非常量的指针",但反过来可以;
> - "常量引用" 不能用于初始化给一个同类型的 "非常量引用",但反过来可以;
>
> ```cpp title:down_level_const.cpp
> int i = 1;
> int *p = &i;
> const int* cp = &i;
> int& ref = i;
> const int& cref = i;
>
> // "底层 const"属性不允许在值传递过程中丢失, 但可以增加.
> // int* p2 = cp; // error: 不能用"指向常量的指针"初始化 or 赋值给"指向非常量的指针"
> const int *cp2 = p; // 但反过来可以.
>
> // int& ref2 = cref; // error: 不能用"常量引用"初始化"非常量引用"
> const int& cref2 = ref; // 但反过来可以
> ```
>
>
<br><br><br>
# `volatile` 修饰符
`volatile` 标识**对象的值可能在 "==程序控制之外==" 被改变**,指示编译器**不应当对访问这一对象的相关代码进行优化**。
> [!info] "**对象的值在程序控制之外被改变**" 是指 "**当前程序代码中未对内存单元进行修改,但==硬件或者其他并行线程可能修改了对象值==**"。
>
> 例如,程序中可能定义了一个位于指定地址,**由系统时钟定时更新的变量**。
> [!NOTE] **==`volatile` 与 `const` 限定符彼此独立==,互不影响,可同时存在**,
>
> 例如,`const volatile` 标识 **==对象的值不能由当前程序修改==(const),但它==可能由程序外的因素修改==(volatile)**。
```cpp
int main() {
volatile int vi; // volatile的int型变量
int* volatile ipv; // 指向int型变量的volatile指针
volatile int *vip; // 指向volatile int型变量的指针
volatile int * volatile vipv; // 指向volatile int型变量的volatile指针
volatile const int vci = 99; // volatile的const int型变量
const int* volatile cipv = nullptr;
volatile int* const vipc = nullptr;
volatile const int* volatile vcipv = nullptr;
const int* volatile const cipvc = nullptr;
volatile const int* volatile const vcipvc = nullptr;
}
```
<br><br>
# Buffer
## 闪念
> sudden idea
## 候选资料
> Read it later
# ♾️参考资料
# Footnotes
[^1]: 《Effective Modern C++》
[^2]: 《C++ Primer》