命名空间
变体
操作

cv constvolatile类型限定符

来自 cppreference.com
< cpp‎ | 语言
 
 
C++ 语言
一般主题
流程控制
条件执行语句
if
迭代语句(循环)
for
range-for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 (直到 C++17*)
noexcept 说明符 (C++11)
异常
命名空间
类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储期说明符
初始化
表达式
替代表示形式
字面量
布尔 - 整数 - 浮点数
字符 - 字符串 - nullptr (C++11)
用户定义 (C++11)
实用程序
属性 (C++11)
类型
typedef 声明
类型别名声明 (C++11)
强制转换
内存分配
类特定函数属性
虚函数
override 说明符 (C++11)  
final 说明符 (C++11)
explicit (C++11)
static

特殊成员函数
模板
模板特化
参数包 (C++11)
杂项
 
 

出现在任何类型说明符中,包括 声明语法decl-specifier-seq,用于指定被声明对象或被命名类型的常量性或易变性。

  • const - 定义类型为*常量*。
  • volatile - 定义类型为*易变的*。

内容

[编辑] 说明

任何(可能是 不完整 的)类型,除了 函数类型引用类型,都是以下四种不同但相关的类型组中的一种类型

  • 一个 *cv-非限定* 版本。
  • 一个 *const-限定* 版本。
  • 一个 *volatile-限定* 版本。
  • 一个 *const-volatile-限定* 版本。

同一组中的这四种类型具有相同的 表示对齐 要求。

数组类型 被认为与其元素类型具有相同的 cv-限定。

[编辑] 常量和易变对象

首次创建对象时,使用的 cv-限定符(可以是 声明decl-specifier-seq声明符 的一部分,或 new 表达式type-id 的一部分)决定对象的常量性或易变性,如下所示

  • 一个 *常量对象* 是
  • 一个类型为 const-限定的对象,或
  • 一个常量对象的非 可变 子对象。
此类对象无法修改:尝试直接修改是编译时错误,而尝试间接修改(例如,通过引用或指向非常量类型的指针修改常量对象)会导致未定义行为。
  • 一个 *易变对象* 是
  • 一个类型为 volatile-限定的对象,
  • 一个易变对象的子对象,或
  • 一个 const-volatile 对象的 可变 子对象。
通过 volatile-限定类型的左值表达式进行的每次访问(读取或写入操作、成员函数调用等)都被视为 优化目的 的可见副作用(也就是说,在单个执行线程中,volatile 访问不能被优化掉,也不能与在 volatile 访问之前或之后 排序 的另一个可见副作用重新排序。这使得 volatile 对象适合与 信号处理程序 通信,但不适合与另一个执行线程通信,请参阅 std::memory_order)。任何尝试通过非常量类型的 左值 访问 volatile 对象(例如,通过引用或指向非常量类型的指针)都会导致未定义行为。
  • 一个 *const volatile 对象* 是
  • 一个类型为 const-volatile-限定的对象,
  • 一个 const volatile 对象的非 可变 子对象,
  • 一个 volatile 对象的 const 子对象,或
  • 一个 const 对象的非 可变 volatile 子对象。
同时表现为常量对象和易变对象。

每个 cv-限定符(constvolatile)在任何 cv-限定符序列中最多只能出现一次。例如,const constvolatile const volatile 不是有效的 cv-限定符序列。

[编辑] mutable 说明符

  • mutable - 允许修改声明为 mutable 的类成员,即使包含对象声明为 const(即,类成员是可变的)。

可以出现在非常量非引用类型的非静态 类成员 的声明中

class X
{
    mutable const int* p; // OK
    mutable int* const q; // ill-formed
    mutable int&       r; // ill-formed
};

mutable 用于指定成员不影响类的外部可见状态(通常用于互斥量、备忘录缓存、惰性求值和访问检测)。

class ThreadsafeCounter
{
    mutable std::mutex m; // The "M&M rule": mutable and mutex go together
    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;
    }
};

[编辑] 转换

cv-限定符之间存在部分排序,按限制增加的顺序排列。可以说类型比以下类型 *更* 或 *更少* cv-限定:

  • *非限定* < const
  • *非限定* < volatile
  • *非限定* < const volatile
  • const < const volatile
  • volatile < const volatile

对 cv-限定类型的引用和指针可以隐式转换为对更多 cv-限定类型的引用和指针,有关详细信息,请参阅 限定转换

要将对 cv-限定类型的引用或指针转换为对更少 cv-限定类型的引用或指针,必须使用 const_cast

[编辑] 注意

在非局部、非易失性、模板(自 C++14 起)内联(自 C++17 起) 变量的声明中使用 const 限定符,并且该变量未声明为 extern,则会赋予其内部链接。这与 C 语言不同,在 C 语言中,const 文件作用域变量具有外部链接。

C++ 语言语法将 mutable 视为存储类说明符,而不是类型限定符,但它不影响存储类或链接。

volatile 的某些用法已被弃用

(自 C++20 起)

[编辑] 关键字

constvolatilemutable

[编辑] 示例

#include <cstdlib>
 
int main()
{
    int n1 = 0;          // non-const object
    const int n2 = 0;    // const object
    int const n3 = 0;    // const object (same as n2)
    volatile int n4 = 0; // volatile object
 
    const struct
    {
        int n1;
        mutable int n2;
    } x = {0, 0};        // const object with mutable member
 
    n1 = 1;   // OK: modifiable object
//  n2 = 2;   // error: non-modifiable object
    n4 = 3;   // OK: treated as a side-effect
//  x.n1 = 4; // error: member of a const object is const
    x.n2 = 4; // OK: mutable member of a const object isn't const
 
    const int& r1 = n1; // reference to const bound to non-const object
//  r1 = 2; // error: attempt to modify through reference to const
    const_cast<int&>(r1) = 2; // OK: modifies non-const object n1
 
    const int& r2 = n2; // reference to const bound to const object
//  r2 = 2; // error: attempt to modify through reference to const
//  const_cast<int&>(r2) = 2; // undefined behavior: attempt to modify const object n2
 
    [](...){}(n3, n4, x, r2); // see also: [[maybe_unused]]
 
    std::system("g++ -O3 -Wa,-adhln ./main.cpp"); // may issue asm on POSIX systems
}

可能的输出

# typical machine code produced on an x86_64 platform
# (only the code that contributes to observable side-effects is emitted)
main:
    movl    $0, -4(%rsp) # volatile int n4 = 0;
    movl    $3, -4(%rsp) # n4 = 3;
    xorl    %eax, %eax   # return 0 (implicit)
    ret

[编辑] 缺陷报告

以下行为更改缺陷报告已追溯应用于以前发布的 C++ 标准。

缺陷报告 应用于 发布时的行为 正确行为
CWG 1428 C++98 “const 对象”的定义基于声明 基于对象类型
CWG 1528 C++98 对同一 cv 限定符序列中每个 cv 限定符的出现次数没有要求
每个 cv 限定符最多出现一次
CWG 1799 C++98 mutable 可以应用于未声明为 const 的数据成员,但成员的类型仍然可以是 const 限定的
不能将 mutable 应用于 const 限定类型的数据成员

[编辑] 另请参阅

C 文档,了解 const 限定符
C 文档,了解 volatile 限定符