Namespaces
Variants

cv ( const and volatile ) type qualifiers

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const / volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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

  • const - 定义该类型为 常量
  • volatile - 定义该类型为 易变

目录

说明

函数类型 引用类型 外,任何(可能为 不完整 的)类型都属于以下四种不同但相关的类型组之一:

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

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

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

const 与 volatile 对象

当对象首次创建时,所使用的cv限定符(可能属于 声明说明符序列 声明 中的 声明符 部分,或是 new表达式 类型标识 的组成部分)将按以下方式决定对象的常量性或易变性:

  • 一个 const 对象
  • 类型被 const 限定的对象,或
  • const 对象的非 mutable 子对象。
此类对象不可被修改:尝试直接修改会导致编译时错误,而尝试间接修改(例如通过非 const 类型的引用或指针修改 const 对象)将导致未定义行为。
  • 一个 volatile 对象
  • 其类型为 volatile 限定的对象,
  • volatile 对象的子对象,或
  • const-volatile 对象的 mutable 子对象。
通过 volatile 限定类型的泛左值表达式进行的每次访问(读写操作、成员函数调用等)均被视为 优化目的 下的可见副作用(即在单线程执行中,volatile 访问不能被优化消除,也不能与在 顺序先后 关系中位于该 volatile 访问之前或之后的另一个可见副作用重新排序)。这使得 volatile 对象适用于与 信号处理程序 通信,但不适用于与其他执行线程通信(参见 std::memory_order )。任何通过非 volatile 类型的 泛左值 (例如通过非 volatile 类型的引用或指针)访问 volatile 对象的行为将导致未定义行为。
  • 一个 const volatile 对象
  • 类型为 const-volatile 限定的对象,
  • const volatile 对象的非 mutable 子对象,
  • volatile 对象的 const 子对象,或
  • const 对象的非 mutable volatile 子对象。
同时表现为 const 对象和 volatile 对象的行为特征。

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

mutable 说明符

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

可能出现在非静态 类成员 的声明中(非引用非const类型):

class X
{
    mutable const int* p; // 正确
    mutable int* const q; // 非法声明
    mutable int&       r; // 非法声明
};

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;
    }
};

转换

存在按限制程度递增的 cv 限定符偏序关系。类型可被称作比以下类型 更多 更少 cv 限定:

  • unqualified < const
  • unqualified < volatile
  • unqualified < const volatile
  • const < const volatile
  • volatile < const volatile
(说明:根据要求,HTML标签、属性及 标签内的C++术语均未翻译,仅翻译了普通文本部分。将"unqualified"译为"无限定符"是C++类型限定符的标准译法)

对 cv 限定类型的引用和指针可以隐式转换为对更多 cv 限定的类型的引用和指针,详见 限定转换

要将引用或指针转换为具有较少 cv 限定符类型的引用或指针,必须使用 const_cast

注释

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

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

volatile 的某些用法已被弃用:

(since C++20)

关键词

const , volatile , mutable

示例

#include <cstdlib>
int main()
{
    int n1 = 0;          // 非常量对象
    const int n2 = 0;    // 常量对象
    int const n3 = 0;    // 常量对象(与 n2 相同)
    volatile int n4 = 0; // 易变对象
    const struct
    {
        int n1;
        mutable int n2;
    } x = {0, 0};        // 带有 mutable 成员的常量对象
    n1 = 1;   // 正确:可修改对象
//  n2 = 2;   // 错误:不可修改对象
    n4 = 3;   // 正确:被视为副作用
//  x.n1 = 4; // 错误:常量对象的成员是常量
    x.n2 = 4; // 正确:常量对象的 mutable 成员不是常量
    const int& r1 = n1; // 绑定到非常量对象的常量引用
//  r1 = 2; // 错误:尝试通过常量引用修改
    const_cast<int&>(r1) = 2; // 正确:修改非常量对象 n1
    const int& r2 = n2; // 绑定到常量对象的常量引用
//  r2 = 2; // 错误:尝试通过常量引用修改
//  const_cast<int&>(r2) = 2; // 未定义行为:尝试修改常量对象 n2
    [](...){}(n3, n4, x, r2); // 另请参阅:[[maybe_unused]]
    std::system("g++ -O3 -Wa,-adhln ./main.cpp"); // 在 POSIX 系统上可能生成汇编代码
}

可能的输出:

# 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限定类型
不能对const限定类型的
数据成员应用 mutable

参见

C 文档 关于 const 限定符
C 文档 关于 volatile 限定符