%% # 纲要 > 主干纲要、Hint/线索/路标 # Q&A #### 已明确 #### 待明确 > 当下仍存有的疑惑 **❓<font color="#c0504d"> 有什么问题?</font>** %% # CV 限定符 > cv 限定符 (cv type qualifiers) cv 限定符是描述变量或对象的**类型说明符**(type specifier),用于指定"**被声明的对象**"或"**被命名的类型**"的 **==常量性==**(constness)或 **==易变性==**(volatility),其指示编译器关于对象如何被访问和修改的信息,**会影响编译器的优化策略**。 "**cv-qualified**" 类型即指带有 `const` 或 `volatile` 或 `const volatile` 修饰符的类型。 C++中,除"**引用**"和"**函数**"类型以外,其余**任何类型**都属于下列四种情形之一: > ![image-20240111174451073|257](_attachment/02-开发笔记/01-cpp/cpp基本概念.assets/IMG-cpp基本概念-1EFCCD03A6EF14BDC6D9290FF09674B4.png) <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》