C++ 参考手册
- C++11
- C++14
- C++17
- C++20
- C++ 编译器支持情况表
- 独立与宿主实现
- C++ 语言
- 变量模板(C++14 起)
- 整数字面量
- 聚合初始化
- 比较运算符
- 默认比较(C++20 起)
- 转义序列
- for 循环
- while 循环
- 用户定义转换
- SFINAE
- 主函数
- ASCII 码表
- 标识符
- 类型
- 内存模型
- 对象
- 基本概念
- 表达式
- 声明
- 初始化
- 函数
- 语句
- 类
- 运算符重载
- 模板
- 异常
- 事务性内存
- 占位符类型说明符 (C++11 起)
- decltype 说明符
- 函数声明
- final 说明符 (C++11 起)
- override 说明符(C++11 起)
- 引用声明
- 移动构造函数
- 移动赋值运算符
- 枚举声明
- constexpr 说明符(C++11 起)
- 列表初始化 (C++11 起)
- 构造函数与成员初始化器列表
- using 声明
- nullptr,指针字面量
- 基础类型
- 类型别名,别名模版 (C++11 起)
- 形参包
- 联合体声明
- 字符串字面量
- 用户定义字面量 (C++11 起)
- 属性说明符序列(C++11 起)
- Lambda 表达式 (C++11 起)
- noexcept 说明符 (C++11 起)
- noexcept 运算符 (C++11 起)
- alignof 运算符(C++11 起)
- alignas 说明符 (C++11 起)
- 存储类说明符
- 基于范围的 for 循环 (C++11 起)
- static_assert 声明
- 隐式转换
- 代用运算符表示
- 自增/自减运算符
- 折叠表达式(C++17 起)
- 类模板实参推导(C++17 起)
- 模板形参与模板实参
- if 语句
- inline 说明符
- 结构化绑定声明 (C++17 起)
- switch 语句
- 字符字面量
- 命名空间
- 求值顺序
- 复制消除
- consteval 说明符 (C++20 起)
- constinit 说明符 (C++20 起)
- 协程 (C++20)
- 模块 (C++20 起)
- 约束与概念 (C++20 起)
- new 表达式
- do-while 循环
- continue 语句
- break 语句
- goto 语句
- return 语句
- 动态异常说明
- throw 表达式
- try 块
- 命名空间别名
- 类声明
- cv(const 与 volatile)类型限定符
- 默认初始化
- 值初始化(C++03 起)
- 零初始化
- 复制初始化
- 直接初始化
- 常量初始化
- 引用初始化
- 值类别
- C++ 运算符优先级
- 布尔字面量
- 浮点字面量
- typedef 说明符
- 显式类型转换
- static_cast 转换
- dynamic_cast 转换
- const_cast 转换
- reinterpret_cast 转换
- delete 表达式
- 构造函数与成员初始化器列表
- this 指针
- 访问说明符
- 友元声明
- virtual 函数说明符
- explicit 说明符
- 静态成员
- 默认构造函数
- 复制构造函数
- 复制赋值运算符
- 析构函数
- 类模板
- 函数模板
- 显式(全)模板特化
- 汇编声明
- C++ 的历史
- 作用域
- 生存期
- 定义与单一定义规则(ODR)
- 名字查找
- 有限定的名字查找
- 无限定的名字查找
- 如同规则
- 未定义行为
- 翻译阶段
- 常量表达式
- 赋值运算符
- 算术运算符
- 逻辑运算符
- 成员访问运算符
- 其他运算符
- sizeof 运算符
- typeid 运算符
- 指针声明
- 数组声明
- 语言链接
- 详述类型说明符
- 默认实参
- 变长实参
- 实参依赖查找
- 重载决议
- 重载函数的地址
- 注入类名
- 非静态数据成员
- 非静态成员函数
- 嵌套类
- 派生类
- 空基类优化
- 抽象类
- 位域
- 转换构造函数
- 成员模板
- 模板实参推导
- 部分模板特化
- sizeof... 运算符
- 待决名
- 函数 try 块
- 扩充命名空间 std
- 字母缩写
- RAII
- 三/五/零之法则
- PImpl
- 零开销原则
- 类型
- 隐式转换
- 注释
- C++ 关键词
- 预处理器
- C++ 标准库头文件
- 具名要求
- 功能特性测试 (C++20)
- 工具库
- 类型支持(基本类型、RTTI、类型特性)
- 概念库 (C++20)
- 错误处理
- 动态内存管理
- 日期和时间工具
- 字符串库
- 容器库
- 迭代器库
- 范围库 (C++20)
- 算法库
- 数值库
- 输入/输出库
- 文件系统库
- 本地化库
- 正则表达式库
- 原子操作库
- 线程支持库
- 实验性 C++ 特性
- 有用的资源
- 索引
- std 符号索引
- 协程支持 (C++20)
- C++ 关键词
存储类说明符
存储类说明符是一个名字的声明语法的 声明说明符序列 的一部分。它与名字的作用域一同,控制名字的二个独立性质:其“存储期”与其“连接”。
|
(C++11 前) |
|
(C++17 前) |
static
- 静态或线程存储期和内部连接。extern
- 静态或线程存储期和外部连接。
|
(C++11 起) |
mutable
- 不影响存储期或连接。解释见 const/volatile 。
声明中只可以出现一个存储类说明符,但 thread_local
可以与 static
或 extern
结合 (C++11 起)。
解释
1) auto 说明符仅在声明于块作用域或函数形参列表中的对象时允许使用。它指示自动存储期,其正是这种声明的缺省情况。此关键词的含义于 C++11 更改。
|
(C++11 前) |
2) register 说明符仅在声明于块作用域或函数形参列表中的对象时允许使用。它指示自动存储期,其正是这种声明的缺省情况。另外,此关键词的存在可用于提示优化器将此变量的值存储于 CPU 寄存器。此关键词于 C++11 被弃用。
|
(C++17 前) |
static
说明符仅在对象声明(除了函数参数列表中)、函数声明(除了块作用域中)及匿名联合体的声明中允许使用。当在类成员的声明中使用时,它声明静态成员。当在对象声明中使用时,它指定静态存储期(除非与 thread_local
协同出现)。在命名空间作用域的声明中使用时,它指定内部连接。extern
声明符仅在变量和函数的声明中允许使用(除了类成员或函数形参)。它指定外部连接,而且技术上不影响存储期,但它不能用于自动存储期的对象的定义,故所有 extern
对象都具有静态或线程存储期。另外,使用 extern
且无初始化器的声明不是定义。
5)
thread_local 关键词只对声明于命名空间作用域的对象、声明于块作用域的对象及静态数据成员允许使用。它指示对象具有线程存储期。它能与 static 或 extern 结合,以分别指定内部或外部连接(但静态数据成员始终拥有外部链接),但额外的 static 不影响存储期。 |
(C++11 起) |
存储期
程序中的所有对象都具有下列存储期之一:
- 自动(automatic)存储期。对象的存储在外围代码块开始时分配,而在结束时解分配。未声明为
static
、extern
或thread_local
的所有局部对象均拥有此存储期。
- 自动(automatic)存储期。对象的存储在外围代码块开始时分配,而在结束时解分配。未声明为
(C++11 起) |
连接
代表对象、引用、函数、类型、模板、命名空间或值的名字,可具有连接。若某个名字具有连接,则其所指代的实体与另一作用域中的声明所引入的同一名字指代相同的实体。若变量、函数或另一实体声明于数个作用域,但没有足够的连接,则将生成该实体的多个实例。
可以识别以下各种连接:
无连接
名字只能从其所在的作用域使用。 声明于块作用域的下列任何名字均无连接:
- 未显式声明为
extern
的变量(无关乎static
修饰符); - 局部类及其成员函数;
- 声明于块作用域的其他名字,例如 typedef、枚举及枚举项。
内部连接
名字可从当前翻译单元中的所有作用域使用。 声明于命名空间作用域的下列任何名字均具有内部连接;
- 声明为
static
的变量、变量模板 (C++14 起)、函数或函数模板; - 不是
extern
的,且先前未声明为具有外部连接的,非 volatile 非模板 (C++14 起)非 inline (C++17 起) 的 const 限定的变量(包含 constexpr); - 匿名联合体的数据成员。
另外,所有声明于无名命名空间或无名命名空间内的命名空间中名字,即使是显式声明为 |
(C++11 起) |
外部连接
名字能从其他翻译单元中的作用域使用。具有外部连接的变量和函数亦具有语言连接,这使得可以连接到以不同编程语言编写的翻译单元。 除了后述注解,声明于命名空间作用域的下列任何名字均具有外部连接
- 以上未列出的变量与函数(即未声明为
static
的函数、命名空间作用域内未声明为static
的非 const 变量,和所有声明为extern
的变量); - 枚举;
- 类名、其成员函数、静态数据成员(不论是否 const)、嵌套类及枚举,及首次以类体内的 friend 声明引入的函数;
- 所有未列于上的模板名(即不声明为
static
的函数模板)。
任何首次声明于块作用域的下列名称拥有外部连接:
- 声明为
extern
的变量名; - 函数名。
然而,若名字声明于无名命名空间或内嵌于无名命名空间的命名空间,则该名字拥有内部连接。若名字声明于具名模块且不被导出,则该名字拥有模块连接。 (C++20 起)
模块连接名字只能从同一模块单元或同一具名模块中的其他翻译单元的作用域指代。 声明于命名空间作用域的名字,若它们声明于具名模块且不被导出,且无内部连接,则拥有模块链接。 |
(C++20 起) |
静态局部变量
声明于块作用域,带说明符 static
或 thread_local
(C++11 起) 的变量拥有静态或线程 (C++11 起)存储期,但在控制首次经过其声明时才得到初始化(除非其初始化是零初始化或常量初始化,这可以在首次进入块前进行)。在其后所有的调用中,声明均被跳过。
若初始化抛出了异常,则不认为变量被初始化,且控制下次经过该声明时,将再次尝试初始化。
若初始化递归地进入正在初始化的变量的块,则行为未定义。
若多个线程试图同时初始化同一静态局部变量,则初始化严格发生一次(类似的行为也可对任意函数以 std::call_once 来达成)。 注意:此功能特性的通常实现均使用双检查锁定模式的变体,这使得对已初始化的局部静态变量检查的运行时开销减少为单次非原子的布尔比较。 |
(C++11 起) |
块作用域静态变量的析构函数在程序退出时执行,但仅若初始化成功发生才执行。
相同内联函数(可以是隐式内联)的所有定义中,函数局域的静态对象全部指代定义于一个翻译单元中的同一对象。
注解
位于顶层命名空间作用域(C 中的文件作用域),且是 const
而非 extern
的名字,在 C 中具有外部连接,但在 C++ 中具有内部连接。
C++11 起,auto
不再是存储类说明符;它被用于指示类型推导。
在 C 中,不能取 |
(C++17 前) |
不同于 C,在 C++ 中不能将变量声明为 |
(C++17 起) |
从不同作用域指涉的,带内部或外部连接的 thread_local
变量的名字,可能指代相同或不同实例,这取决于代码执行于相同还是不同的线程。
extern
关键词亦可用于指定语言连接和显式模板实例化声明,但它在这些情况中不是存储类说明符(但当声明直接在语言连接说明中所包含时,该情况下将声明当做如同它含 extern
说明符)。
关键词 mutable
在 C++ 语言的文法中是存储类说明符,尽管它并不影响存储期或连接。
本节未完成 原因:有关在同一翻译单元中重声明一个名字的规则 |
存储类说明符除了 thread_local
,都不允许在显式特化及显式实例化中使用:
template <class T> struct S { thread_local static int tlm; }; template <> thread_local int S<float>::tlm = 0; // "static" 不出现于此
关键词
auto, register, static, extern, thread_local, mutable
示例
#include <iostream> #include <string> #include <thread> #include <mutex> thread_local unsigned int rage = 1; std::mutex cout_mutex; void increase_rage(const std::string& thread_name) { ++rage; // 在锁外修改 OK;这是线程局域变量 std::lock_guard<std::mutex> lock(cout_mutex); std::cout << "Rage counter for " << thread_name << ": " << rage << '\n'; } int main() { std::thread a(increase_rage, "a"), b(increase_rage, "b"); { std::lock_guard<std::mutex> lock(cout_mutex); std::cout << "Rage counter for main: " << rage << '\n'; } a.join(); b.join(); }
可能的输出:
Rage counter for a: 2 Rage counter for main: 1 Rage counter for b: 2
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
DR | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
CWG 2387 | C++14 | 不明确 const 限定的变量模板是否默认有内部连接 | const 限定符不影响变量模板或其实例的连接 |