024 C++的关键词系统性学习笔记
1
deepseek prompts:
2
3
请生成系统性、结构化的学习教程,要求涵盖各个知识点。关于:c++的关键词。
4
要求如下:
5
1. 不要使用markdown的列表语法;
6
2. 推荐使用序号: ㈠ 、①、ⓐ 等等;
7
3. 允许使用表格、代码块、emoji、注释;
8
4. 不能遗漏任何知识点;
1. 简介
C++ 关键词是语言中预定义的保留字,具有特殊含义,不能用作标识符(如变量名、函数名等)。本教程将系统介绍 C++ 的关键词,分类讲解其用途和示例。
2. C++ 关键词分类及详解
以下是根据要求生成的C++关键词系统性学习教程,采用结构化序号和表格展示,包含所有C++关键词(截至C++20标准)并附代码示例:
㈠ 基础关键词(存储类与类型相关)
表格1:基本类型与存储类关键词
关键词 | 作用描述 🔍 | 代码示例 💻 | 注意事项 ⚠️ |
---|---|---|---|
auto | 自动类型推导 🚀 | auto x = 5; | C++11起支持 |
bool | 布尔类型 ✅ | bool flag = true; | 值只能是true/false |
char | 字符类型 🔤 | char c = 'A'; | 通常占1字节 |
const | 定义常量 🔒 | const int MAX = 100; | 必须初始化 |
double | 双精度浮点 🏊 | double pi = 3.14159; | 精度约15位 |
float | 单精度浮点 🏄 | float f = 1.23f; | 后缀f可选 |
int | 整型 🔢 | int count = 10; | 大小依赖平台 |
mutable | 可变成员 🔄 | mutable int cache; | 用于const对象 |
short | 短整型 📏 | short s = 32767; | 通常16位 |
signed | 有符号类型 ➕ | signed char sc = -1; | 默认修饰整型 |
static | 静态存储期 ⏳ | static int counter = 0; | 生命周期为整个程序 |
unsigned | 无符号类型 ➖ | unsigned int ui = 42; | 不能表示负数 |
void | 无类型 ❌ | void func(); | 不能声明void变量 |
volatile | 易变变量 ⚡ | volatile int* p; | 防止编译器优化 |
㈡ 复合类型与运算符相关
① 类型修饰与运算符
表格2:复合类型关键词
关键词 | 典型用法 🛠️ | 示例代码 🧩 | 重要特性 ✨ |
---|---|---|---|
char16_t | UTF-16字符 🈁 | char16_t uc = u'好'; | C++11新增 |
char32_t | UTF-32字符 🈲 | char32_t uc = U'😊'; | C++11新增 |
char8_t | UTF-8字符 🈴 | char8_t c = u8'a'; | C++20新增 |
decltype | 表达式类型推导 🔍 | decltype(x) y = x; | C++11新增 |
wchar_t | 宽字符 🌐 | wchar_t wc = L'中'; | 大小依赖平台 |
② 类型转换
表格3:类型转换关键词
关键词 | 转换类型 🔄 | 代码示例 🧪 | 安全性 🛡️ |
---|---|---|---|
dynamic_cast | 多态类型转换 🦄 | Derived* d = dynamic_cast<Derived*>(base); | 运行时检查 |
reinterpret_cast | 重解释转换 🧙 | int i = reinterpret_cast<int>(ptr); | 最不安全 |
static_cast | 静态类型转换 🏗️ | float f = static_cast<float>(i); | 编译时检查 |
const_cast | 常量性移除 🗝️ | char* p = const_cast<char*>(str); | 仅修改const属性 |
㈢ 流程控制结构
ⓐ 分支结构
表格4:分支控制关键词
关键词 | 控制结构 🌉 | 示例代码 🎮 | 替代方案 🔀 |
---|---|---|---|
if | 条件判断 ❓ | if (x > 0) {...} | 三元运算符 |
else | 否则分支 ➰ | else { ... } | 必须配合if |
switch | 多路分支 🚦 | switch(val) { case 1:... } | if-else链 |
case | 分支标签 🏷️ | case 1: break; | 必须整数常量 |
default | 默认分支 ⚖️ | default: ... | 应放在最后 |
ⓑ 循环结构
表格5:循环控制关键词
关键词 | 循环类型 🔁 | 示例代码 🎯 | 注意事项 🚨 |
---|---|---|---|
do | 后测试循环 🔄 | do { ... } while(x); | 至少执行一次 |
for | 计数循环 🔢 | for(int i=0; i<10; ++i) | C++11支持范围for |
while | 前测试循环 🔍 | while(cond) { ... } | 可能不执行 |
break | 循环中断 ⛔ | if(x) break; | 跳出当前循环 |
continue | 跳过本次 ↪️ | if(x) continue; | 进入下次迭代 |
㈣ 面向对象特性
表格6:类相关关键词
关键词 | OOP概念 🧩 | 示例代码 🏛️ | 版本要求 📌 |
---|---|---|---|
class | 类定义 📦 | class MyClass {}; | 默认private继承 |
struct | 结构体 🧱 | struct Point { int x,y; }; | 默认public继承 |
union | 联合体 🤝 | union { int i; float f; }; | 共享内存 |
enum | 枚举 🎚️ | enum Color { RED, GREEN }; | C++11新增enum class |
explicit | 显式转换 🚫 | explicit MyClass(int); | 禁止隐式转换 |
friend | 友元 👬 | friend class FriendClass; | 破坏封装性 |
inline | 内联函数 ⚡ | inline void f() {...} | 建议而非命令 |
namespace | 命名空间 📁 | namespace NS { ... } | 避免名称冲突 |
operator | 运算符重载 ⚖️ | Vector operator+(Vector); | 不能创建新运算符 |
private | 私有成员 🔐 | private: int secret; | 默认class可见性 |
protected | 保护成员 🛡️ | protected: int value; | 派生类可访问 |
public | 公共成员 👐 | public: void func(); | 默认struct可见性 |
template | 模板 📜 | template<typename T> class Box; | 泛型编程 |
this | 当前对象 👤 | return *this; | 指针形式访问 |
virtual | 虚函数 👻 | virtual void draw(); | 实现多态 |
㈤ 异常处理
表格7:异常处理关键词
关键词 | 异常处理 🚨 | 示例代码 🆘 | 最佳实践 ✅ |
---|---|---|---|
try | 异常检测 🕵️ | try { risky(); } | 应尽量缩小范围 |
catch | 异常捕获 🎣 | catch(Exception& e) {...} | 按派生类到基类顺序 |
throw | 抛出异常 💥 | throw std::runtime_error("msg"); | C++11推荐noexcept |
noexcept | 不抛异常 🚫 | void func() noexcept; | C++11新增 |
㈥ 内存管理
表格8:内存管理关键词
关键词 | 内存操作 💾 | 示例代码 🧠 | 现代替代方案 🆕 |
---|---|---|---|
new | 动态分配 🆕 | int* p = new int(10); | 智能指针 |
delete | 释放内存 🗑️ | delete p; | 智能指针 |
new[] | 数组分配 📊 | int* arr = new int[10]; | std::vector |
delete[] | 数组释放 🗂️ | delete[] arr; | std::vector |
㈦ C++11/14/17/20新增关键词
表格9:现代C++新增关键词
关键词 | 版本 🏷️ | 用途 🎯 | 示例代码 🚀 |
---|---|---|---|
alignas | C++11 | 对齐控制 ⬆️ | alignas(16) struct S {}; |
alignof | C++11 | 获取对齐量 📏 | size_t a = alignof(double); |
concept | C++20 | 模板约束 🎚️ | template<Number T> void f(T); |
consteval | C++20 | 立即函数 ⚡ | consteval int sqr(int n) { return n*n; } |
constexpr | C++11 | 编译期计算 ⏱️ | constexpr int fac(int n) {...} |
constinit | C++20 | 常量初始化 🏁 | constinit static int x = 42; |
co_await | C++20 | 协程等待 ⏸️ | int val = co_await future; |
co_return | C++20 | 协程返回 🔙 | co_return 42; |
co_yield | C++20 | 协程产出 🌾 | co_yield value; |
requires | C++20 | 概念约束 🔗 | requires Integral<T> {...} |
thread_local | C++11 | 线程存储 🧵 | thread_local int counter; |
㈧ 其他关键词
表格10:杂项关键词
关键词 | 特殊用途 🎭 | 示例代码 🧪 | 使用场景 🌐 |
---|---|---|---|
asm | 内联汇编 💻 | asm("mov eax, 1"); | 平台相关 |
bitand | 替代运算符 & | c = a bitand b; | 极少使用 |
bitor | 替代运算符 | c = a bitor b; | |
compl | 替代运算符 ~ | x = compl y; | 极少使用 |
not | 替代运算符 ! | if (not flag)... | 可读性差 |
not_eq | 替代运算符 != | if (a not_eq b)... | 可读性差 |
or | 替代运算符 | ||
xor | 替代运算符 ^ | c = a xor b; | 极少使用 |
and | 替代运算符 && | if (a and b)... | 可读性差 |
and_eq | 替代运算符 &= | a and_eq b; | 极少使用 |
or_eq | 替代运算符 | = | a or_eq b; |
xor_eq | 替代运算符 ^= | a xor_eq b; | 极少使用 |
3 C++ 关键词完整列表
以下是 C++ 标准(C++17) 中定义的 完整关键词列表(共 84 个),按字母顺序排列,并标注了 C++11/14/17 新增的关键词:
关键词 | 用途说明(简要) | 标准版本 |
---|---|---|
alignas | 指定变量或类型的对齐要求 | C++11 |
alignof | 获取类型的对齐要求 | C++11 |
and | 逻辑运算符(替代 && ) | C++11 |
and_eq | 复合赋值运算符(&= ) | - |
asm | 内联汇编代码(平台相关) | - |
auto | 自动类型推导(或旧版存储类) | C++11(语义变更) |
bitand | 位运算符(& ) | - |
bitor | 位运算符(\| ) | - |
bool | 布尔类型(true /false ) | - |
break | 跳出循环或 switch | - |
case | switch 语句的分支 | - |
catch | 异常处理捕获块 | - |
char | 字符类型 | - |
char16_t | UTF-16 字符类型 | C++11 |
char32_t | UTF-32 字符类型 | C++11 |
class | 定义类或模板参数 | - |
compl | 位取反运算符(~ ) | - |
const | 常量修饰符 | - |
constexpr | 编译时常量或函数 | C++11 |
const_cast | 常量类型转换 | - |
continue | 跳过当前循环迭代 | - |
decltype | 推导表达式类型 | C++11 |
default | switch 默认分支或默认函数实现 | - |
delete | 释放动态内存或删除函数 | - |
do | do-while 循环 | - |
double | 双精度浮点类型 | - |
dynamic_cast | 动态类型转换(多态) | - |
else | if 语句的备用分支 | - |
enum | 枚举类型定义 | - |
explicit | 禁止隐式转换(构造函数或转换函数) | - |
export | 模板导出(已弃用,C++11 后仅用于模块) | - |
extern | 声明外部链接 | - |
false | 布尔字面量 | - |
float | 单精度浮点类型 | - |
for | for 循环 | - |
friend | 友元声明(允许访问私有成员) | - |
goto | 无条件跳转 | - |
if | 条件语句 | - |
inline | 内联函数或变量(C++17) | - |
int | 整数类型 | - |
long | 长整型修饰符 | - |
mutable | 允许 const 成员变量被修改 | - |
namespace | 命名空间定义 | - |
new | 动态内存分配 | - |
noexcept | 指定函数不抛出异常 | C++11 |
not | 逻辑非(替代 ! ) | C++11 |
not_eq | 不等运算符(!= ) | - |
nullptr | 空指针字面量 | C++11 |
operator | 重载运算符 | - |
or | 逻辑或(替代 \|\| ) | C++11 |
or_eq | 复合赋值运算符(\|= ) | - |
private | 类成员的私有访问权限 | - |
protected | 类成员的保护访问权限 | - |
public | 类成员的公共访问权限 | - |
register | 建议编译器将变量存储在寄存器中(C++17 弃用) | - |
reinterpret_cast | 低层类型转换(危险操作) | - |
return | 函数返回值 | - |
short | 短整型修饰符 | - |
signed | 有符号类型修饰符 | - |
sizeof | 获取类型或对象的大小 | - |
static | 静态变量或函数 | - |
static_assert | 编译时断言 | C++11 |
static_cast | 静态类型转换(安全转换) | - |
struct | 定义结构体或模板参数 | - |
switch | 多路分支语句 | - |
template | 模板定义 | - |
this | 指向当前对象的指针 | - |
thread_local | 线程局部存储 | C++11 |
throw | 抛出异常 | - |
true | 布尔字面量 | - |
try | 异常处理尝试块 | - |
typedef | 类型别名(C++11 后可用 using 替代) | - |
typeid | 获取类型信息(RTTI) | - |
typename | 指定模板中的依赖类型名 | - |
union | 联合体定义 | - |
unsigned | 无符号类型修饰符 | - |
using | 类型别名或引入命名空间 | - |
virtual | 虚函数或虚继承 | - |
void | 无类型或空参数 | - |
volatile | 防止编译器优化(多线程或硬件相关) | - |
wchar_t | 宽字符类型 | - |
while | while 循环 | - |
xor | 位异或(^ ) | - |
xor_eq | 复合赋值运算符(^= ) | - |
注意事项
1. C++20 新增关键词(未在上表中列出):
- concept
、requires
、consteval
、co_await
、co_yield
、co_return
(协程相关)。
2. 废弃关键词:
- register
(C++17 起弃用)。
3. 替代运算符:
- and
、or
、not
等是运算符的别名,可增强代码可读性。
4. using 关键词用法
下面针对C++中的 using
关键字进行系统性讲解,涵盖其所有核心用法和场景,结合代码示例和对比分析:
㈠ using
关键字的核心用途概览 🔍
表格1:using
的四大核心功能
用途分类 | 典型场景 🎯 | 对比替代方案 🔀 | 版本要求 📌 |
---|---|---|---|
类型别名 | 简化复杂类型名 | typedef (C++98) | C++11 |
命名空间引入 | 避免重复写命名空间前缀 | namespace ns = ... | C++98 |
继承中的成员引入 | 调整基类成员的可访问性 | 直接重写成员函数 | C++11 |
模板别名 | 简化模板类型 | 无直接等价方案 | C++11 |
㈡ 类型别名(Type Alias) ✏️
① 基本用法(替代 typedef
)
1
// C++98 的 typedef
2
typedef std::vector<std::map<int, std::string>> LegacyType;
3
4
// C++11 的 using(更清晰)
5
using ModernType = std::vector<std::map<int, std::string>>;
优势对比:
- 可读性更强(类似变量赋值的语法)
- 支持模板别名(typedef
无法实现)
② 函数指针别名
1
using Callback = void (*)(int, const std::string&);
2
// 使用示例
3
void register_callback(Callback cb) {
4
cb(42, "Hello");
5
}
㈢ 命名空间管理 🗂️
① 引入整个命名空间(谨慎使用)
1
namespace mylib {
2
void foo() { std::cout << "mylib::foo\n"; }
3
}
4
5
using namespace mylib; // 全部引入
6
foo(); // 直接调用
② 选择性引入成员
1
using std::cout, std::endl; // C++17 多重引入
2
cout << "Hello" << endl;
③ 命名空间别名
1
namespace very_long_namespace_name { /*...*/ }
2
using vln = very_long_namespace_name; // 缩写
3
vln::some_function();
㈣ 继承中的成员引入(Inheritance Control) 👨👦
① 调整基类成员可见性
1
class Base {
2
protected:
3
void secret() { std::cout << "Base secret\n"; }
4
};
5
6
class Derived : public Base {
7
public:
8
using Base::secret; // 将protected提升为public
9
};
10
11
Derived d;
12
d.secret(); // 现在可以公开访问
② 解决重载隐藏问题
1
class Base {
2
public:
3
void func(int) { std::cout << "Base::func(int)\n"; }
4
};
5
6
class Derived : public Base {
7
public:
8
using Base::func; // 引入所有重载
9
void func(double) { std::cout << "Derived::func(double)\n"; }
10
};
11
12
Derived d;
13
d.func(1); // 调用Base::func(int)
14
d.func(1.0); // 调用Derived::func(double)
㈤ 模板别名(Template Alias) 🧩
① 简化模板类型
1
template<typename T>
2
using StringMap = std::map<std::string, T>; // 模板别名
3
4
StringMap<int> m1; // 等价于 std::map<std::string, int>
5
StringMap<double> m2;
② 结合 typename
解决依赖类型
1
template<typename Container>
2
using ValueType = typename Container::value_type; // 必须加typename
3
4
template<typename C>
5
void print_first(const C& c) {
6
ValueType<C> elem = c.front(); // 更清晰
7
std::cout << elem;
8
}
㈥ 特殊用法与技巧 🎨
① 配合 decltype
创建类型别名
1
auto complexFunc() -> std::pair<int, std::string>;
2
using ResultType = decltype(complexFunc()); // 自动推导返回类型
② 类型萃取(Type Traits)
1
template<typename T>
2
using RemovePtr = std::remove_pointer_t<T>; // C++14风格
3
4
RemovePtr<int*> x; // x的类型是int
③ 变长模板参数包
1
template<typename... Ts>
2
using Tuple = std::tuple<std::vector<Ts>...>; // 对每个类型套vector
3
Tuple<int, float> t; // 实际是 std::tuple<vector<int>, vector<float>>
㈦ 注意事项与最佳实践 ⚠️
命名空间污染
1
// 避免在头文件使用(影响所有包含该头文件的代码)
2
using namespace std; // ❌ 危险用法
优先选择 using
而非 typedef
- 更一致的语法(从左到右阅读)
- 支持模板等现代特性
继承中的 using
声明顺序
1
class Derived : Base {
2
using Base::func; // 先引入基类重载
3
void func(double); // 再添加新重载
4
};
模板别名与类型推导
1
template<typename T>
2
using Ptr = T*;
3
4
Ptr<int> p1; // OK: int*
5
Ptr<void> p2; // OK: void*
6
Ptr<auto> p3; // ❌ 错误:不能推导
㈧ 综合对比表 📊
表格2:using
vs typedef
vs namespace
特性 | using | typedef | namespace |
---|---|---|---|
类型别名 | ✅ 语法清晰 | ⚠️ 语法受限 | ❌ 不适用 |
模板别名 | ✅ 完全支持 | ❌ 不支持 | ❌ 不适用 |
命名空间缩写 | ✅ using ns = ... | ❌ 不适用 | ✅ 原生支持 |
成员函数引入 | ✅ 继承控制 | ❌ 不适用 | ❌ 不适用 |
可读性 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
5. static关键词用法
㈠ 基本概念
static
是C++中的存储类说明符,用于控制变量或函数的存储期和可见性。它的含义根据使用场景不同而变化,主要分为以下四种用法:
① 静态局部变量
在函数内部声明,生命周期延长至程序结束,但作用域仍限于函数内:
1
void foo() {
2
static int count = 0; // ⓵ 只初始化一次
3
count++;
4
cout << count << endl;
5
}
6
// 调用 foo() 多次会输出递增的值(1, 2, 3...)
ⓐ 特点:
- 内存分配在全局数据区,程序结束时释放
- 默认初始化为0(如 static int x;
的 x
值为0)
② 静态全局变量/函数
在文件作用域内使用,限制符号仅在本文件内可见(内部链接):
1
// File1.cpp
2
static int hiddenVar = 42; // ⓶ 其他文件无法访问
3
static void helper() {} // ⓷ 仅限本文件调用
ⓑ 对比普通全局变量:
普通全局变量可通过 extern
跨文件访问,静态全局变量则不能。
③ 静态成员变量
属于类而非对象,所有实例共享同一内存:
1
class Widget {
2
public:
3
static int instanceCount; // ⓸ 声明
4
};
5
int Widget::instanceCount = 0; // ⓹ 必须在类外定义
ⓒ 关键规则:
- 必须在类外单独定义(分配内存)
- 可通过 类名::变量名
或 对象.变量名
访问
④ 静态成员函数
无 this
指针,只能访问静态成员:
1
class Logger {
2
public:
3
static void log(const string& msg) { // ⓺
4
cout << msg;
5
// cout << id; ❌ 错误!不能访问非静态成员
6
}
7
private:
8
int id;
9
};
ⓓ 使用场景:
- 工具类操作(如数学计算)
- 单例模式实现
㈡ 底层机制
① 内存分配:
所有静态数据(局部/全局/类成员)均存储在程序的 数据段(BSS段或已初始化数据段)。
② 初始化时机:
- 局部静态变量:首次执行到声明处时初始化(线程安全)
- 全局/类静态变量:main()
函数前初始化
㈢ 进阶用法
① 静态断言(C++11)
编译时检查条件(非 static
关键词相关,但名称易混淆):
1
static_assert(sizeof(int) == 4, "int must be 4 bytes"); // ⓻
② 模板中的静态成员
每个模板实例化版本拥有独立的静态成员:
1
template<typename T>
2
class Box {
3
public:
4
static int count;
5
};
6
template<typename T> int Box<T>::count = 0;
7
// Box<int>::count 与 Box<float>::count 是不同的变量
㈣ 对比表格
场景 | 生命周期 | 作用域 | 典型用途 |
---|---|---|---|
静态局部变量 | 程序整个运行期 | 函数内部 | 计数器、缓存 |
静态全局变量 | 程序整个运行期 | 文件内部 | 隐藏实现细节 |
静态成员变量 | 程序整个运行期 | 类作用域 | 对象计数、共享配置 |
静态成员函数 | - | 类作用域 | 工具函数、单例访问点 |
㈤ 注意事项
⚠️ 线程安全:
- C++11起,局部静态变量初始化是线程安全的
- 但多线程修改静态变量仍需手动加锁
⚠️ 初始化顺序:
不同文件的全局静态变量初始化顺序不确定,可能导致"静态初始化顺序灾难"。
示例问题:
1
// FileA.cpp
2
static int x = 100;
3
// FileB.cpp
4
extern int x;
5
static int y = x + 1; // ❌ 可能未初始化
6. constexpr 关键词用法
㈠ 基本概念
constexpr
是C++11引入的关键词,用于声明编译时常量或编译时可计算的表达式/函数。核心目标是让计算在编译阶段完成,提升运行时效率。
① 核心特性
ⓐ 必须能在编译期求值
ⓑ 可修饰变量、函数、构造函数
ⓒ C++14放宽了部分限制(如允许循环、局部变量)
㈡ constexpr变量
① 基本用法
1
constexpr int size = 10; // ⓵ 编译期常量
2
constexpr double pi = 3.1415926; // ⓶ 浮点数也可
3
int arr[size]; // ✅ 合法,数组大小需编译期确定
② 与const的区别
特性 | constexpr | const |
---|---|---|
求值时机 | 必须编译期 | 可运行期 |
数组大小声明 | ✅ 可用 | ❌ 除非本身是constexpr |
类型要求 | 必须是字面类型 | 无限制 |
示例:
1
int x = 5;
2
const int a = x; // ✅ 运行期初始化
3
constexpr int b = x; // ❌ 错误!x不是编译期常量
㈢ constexpr函数
① 函数要求
ⓐ C++11:函数体只能包含单一return语句
ⓑ C++14:允许循环、局部变量、分支等
1
// C++11风格
2
constexpr int factorial(int n) {
3
return n <= 1 ? 1 : n * factorial(n - 1); // ⓷ 递归实现
4
}
5
6
// C++14风格
7
constexpr int pow(int base, int exp) {
8
int result = 1; // ⓸ 允许局部变量
9
for (int i = 0; i < exp; ++i) result *= base;
10
return result;
11
}
② 使用场景
1
constexpr int val = factorial(5); // ⓹ 编译时计算
2
std::array<int, pow(2, 3)> arr; // ⓺ 模板参数中使用
㈣ constexpr构造函数
① 要求
ⓐ 所有成员必须初始化
ⓑ 函数体必须为空
1
class Point {
2
public:
3
constexpr Point(int x, int y) : x_(x), y_(y) {} // ⓻
4
constexpr int x() const { return x_; }
5
private:
6
int x_, y_;
7
};
8
9
constexpr Point p(1, 2); // ⓼ 编译期创建对象
10
constexpr int x = p.x(); // ⓽ 编译期调用成员函数
㈤ C++17/20增强
① if constexpr(C++17)
编译期条件分支,丢弃未选择的分支代码:
1
template<typename T>
2
auto print(T val) {
3
if constexpr (std::is_integral_v<T>) { // ⓾
4
cout << "整数: " << val;
5
} else {
6
cout << "其他: " << val;
7
}
8
}
② consteval(C++20)
强制函数必须在编译期执行:
1
consteval int strict_pow(int base, int exp) { // ⓫
2
return pow(base, exp);
3
}
4
// strict_pow(2, 3) ✅
5
// int x = 3; strict_pow(2, x) ❌ 参数必须编译期已知
㈥ 底层机制
① 编译期计算原理
编译器在语法分析阶段展开constexpr表达式,生成常量结果直接嵌入代码。
② 错误检测
违反constexpr要求的代码会直接导致编译错误:
1
constexpr int fail() {
2
int* p = new int(42); // ⓬ ❌ 不允许动态内存分配
3
return *p;
4
}
㈦ 典型应用场景
① 模板元编程中的计算
② 替代宏定义的常量
③ 高性能数学运算(如游戏引擎中的向量计算)
④ 编译期字符串处理(C++17后)
㈧ 限制与注意事项
⚠️ 不可用操作
- 动态内存分配(new/delete)
- 异常处理
- 非constexpr函数调用
- I/O操作
⚠️ 调试技巧
使用static_assert
验证constexpr结果:
1
static_assert(factorial(5) == 120, "编译期计算错误"); // ⓭
7. alignas 关键词用法
㈠ 基本概念
alignas
是C++11引入的内存对齐控制关键词,用于显式指定变量或类型的对齐要求。其核心目的是优化内存访问效率或满足硬件特定需求(如SIMD指令)。
① 语法形式
1
alignas(alignment) 类型/变量声明; // ⓵ 基本语法
2
alignas(常量表达式) 类型/变量声明; // ⓶ 支持常量表达式
㈡ 核心特性
① 对齐值要求
ⓐ 必须是2的幂次方(1, 2, 4, 8...)
ⓑ 不得超过实现定义的最大对齐(可通过alignof(std::max_align_t)
查询)
② 作用目标
可应用于:
ⓐ 变量声明
ⓑ 类/结构体成员
ⓒ 整个类/结构体
ⓓ 数组元素
㈢ 典型用法示例
① 基本变量对齐
1
alignas(16) float vec[4]; // ⓷ 确保数组按16字节对齐
② 结构体成员对齐
1
struct Data {
2
char id;
3
alignas(8) double value; // ⓸ 强制value从8字节边界开始
4
};
③ 类型整体对齐
1
struct alignas(32) CacheLine { // ⓹ 整个结构体32字节对齐
2
char data[32];
3
};
㈣ 底层机制
① 对齐实现原理
编译器在内存分配时插入填充字节(padding),确保起始地址满足对齐要求。例如:
1
struct alignas(8) Example {
2
char a; // 偏移0
3
// 编译器插入7字节填充
4
double b; // 偏移8
5
};
② 与相关运算符的关系
运算符 | 作用 | 示例 |
---|---|---|
alignof | 查询类型的对齐要求 | alignof(Data) → 8 |
std::alignment_of | 类型特性的对齐查询 | std::alignment_of_v<int> |
㈤ 高级用法
① 动态对齐需求处理
结合std::aligned_storage
实现动态内存对齐:
1
std::aligned_storage<sizeof(Data), alignof(Data)>::type storage; // ⓺
② SIMD指令优化
为AVX指令要求32字节对齐:
1
alignas(32) float simd_data[8]; // ⓻ 适合_mm256_load_ps指令
㈥ 注意事项
⚠️ 过度对齐风险
对齐值超过平台最大支持值时行为由实现定义(可能忽略或报错):
1
alignas(1024) int x; // ⓼ 可能被编译器拒绝
⚠️ 与#pragma pack冲突
#pragma pack
会临时修改默认对齐,可能覆盖alignas
效果:
1
#pragma pack(1)
2
struct S {
3
alignas(8) char c; // ⓽ 实际可能仍为1字节对齐
4
};
5
#pragma pack()
㈦ 实际应用场景
① 硬件寄存器映射(如嵌入式开发)
② 高性能计算(SSE/AVX指令集)
③ 避免缓存行伪共享(多线程优化)
④ 网络协议数据包解析
㈧ 跨平台兼容性
不同架构的默认对齐差异:
架构 | 典型最大对齐要求 |
---|---|
x86-64 | 16字节 |
ARMv8 | 16字节 |
GPU架构 | 128字节或更高 |
8. alignof 关键词用法
㈠ 基本概念
alignof
是C++11引入的运算符,用于查询类型的对齐要求(alignment requirement)。它返回std::size_t
类型的值,表示该类型实例在内存中分配时的起始地址必须能被多少整除。
① 语法形式
1
alignof(类型) // ⓵ 基本用法
㈡ 核心特性
① 返回值特性
ⓐ 返回值总是2的幂次方(1, 2, 4, 8...)
ⓑ 对引用类型返回引用对象的对齐值
ⓒ 对数组类型返回元素类型的对齐值
② 特殊类型处理
1
alignof(void) // ⓶ 通常返回1,但标准未明确规定
2
alignof(char) // ⓷ 保证返回1(char总是字节对齐)
㈢ 典型用法示例
① 基本类型对齐查询
1
cout << alignof(int); // ⓸ 通常输出4(32位系统)或8(64位系统)
2
cout << alignof(double); // ⓹ 通常输出8
② 结构体对齐分析
1
struct Foo {
2
char c; // 1字节
3
double d; // 8字节
4
};
5
cout << alignof(Foo); // ⓺ 输出8(由最大成员d决定)
③ 与sizeof对比
运算符 | 作用 | 示例(struct Foo) |
---|---|---|
sizeof | 获取类型存储大小 | 16(1+7padding+8) |
alignof | 获取类型对齐要求 | 8 |
㈣ 底层实现原理
① 编译器行为
编译器根据目标平台ABI规范确定对齐值,x86-64常见对齐规则:
1
// 伪代码表示编译器决策逻辑
2
if (类型==SIMD类型) return 32;
3
else if (类型==double) return 8;
4
else if (类型==指针) return 8;
5
else return 默认对齐;
② 与alignas的关系
alignof
可以验证alignas
的效果:
1
struct alignas(16) Bar {};
2
static_assert(alignof(Bar) == 16, "对齐失败"); // ⓻
㈤ 高级应用场景
① 内存池优化
自定义内存分配器时确保对齐:
1
template<typename T>
2
void* allocate() {
3
const size_t align = alignof(T); // ⓼
4
return aligned_alloc(align, sizeof(T));
5
}
② 跨平台兼容处理
检查不同平台的对齐差异:
1
#if alignof(long double) > 8
2
// 处理特殊对齐需求
3
#endif
㈥ 注意事项
⚠️ 与reinterpret_cast的陷阱
错误的对齐访问可能导致未定义行为:
1
char buffer[32];
2
auto p = reinterpret_cast<double*>(buffer); // ⓽ 可能未对齐
3
*p = 3.14; // 可能崩溃(如buffer地址不是8的倍数)
⚠️ C++17结构化绑定
对齐信息会保留:
1
struct Point { double x, y; };
2
auto [x, y] = Point{}; // ⓾ x/y仍保持8字节对齐
㈦ 平台差异参考
常见平台对齐值对比(单位:字节):
类型 | x86-64 | ARMv8 | 备注 |
---|---|---|---|
bool | 1 | 1 | |
int | 4 | 4 | |
double | 8 | 8 | |
__m128 (SSE) | 16 | - | ARM需NEON指令支持 |
std::string | 8 | 8 | 实际取决于实现 |
9. auto 关键词用法
㈠ 基本概念
auto
是C++11引入的类型推导关键字,用于让编译器自动推断变量或表达式的类型。它的核心目的是简化代码编写,特别是在处理复杂类型时。
① 语法形式
1
auto 变量名 = 表达式; // ⓵ 基本语法
2
auto&& 变量名 = 表达式; // ⓶ 通用引用形式
㈡ 核心特性
① 类型推导规则
ⓐ 去除顶层const和引用
ⓑ 保留底层const
ⓒ 数组退化为指针
ⓓ 函数退化为函数指针
② 典型用法
1
auto i = 42; // ⓷ int
2
auto d = 3.14; // ⓸ double
3
auto s = "hello"; // ⓹ const char*
4
const auto& rs = s; // ⓺ const char* const&
㈢ 高级用法
① 函数返回类型推导
C++14允许函数返回类型使用auto:
1
auto add(int a, int b) { // ⓻
2
return a + b; // 返回类型推导为int
3
}
② decltype(auto)
C++14引入,保留完整类型信息:
1
int x = 10;
2
int& getRef() { return x; }
3
auto a = getRef(); // ⓼ int
4
decltype(auto) b = getRef(); // ⓽ int&
㈣ 与模板结合
① 通用lambda表达式
C++14支持auto参数:
1
auto print = [](auto val) { // ⓾
2
std::cout << val;
3
};
4
print(42); // 实例化为int
5
print("text"); // 实例化为const char*
② 结构化绑定
C++17支持auto解包:
1
std::pair<int, double> p{1, 2.5};
2
auto [x, y] = p; // ⓫ x:int, y:double
㈤ 注意事项
⚠️ 初始化要求
auto变量必须初始化:
1
auto x; // ⓬ ❌ 错误!必须初始化
⚠️ 类型推导陷阱
代理类可能导致意外行为:
1
vector<bool> v{true, false};
2
auto b = v[0]; // ⓭ 实际类型是vector<bool>::reference
㈥ 性能考量
① 与具体类型对比
声明方式 | 可读性 | 维护性 | 性能影响 |
---|---|---|---|
auto | 中 | 高 | 无 |
显式类型 | 高 | 中 | 无 |
auto&& | 低 | 高 | 可能优化 |
② 移动语义优化
auto可以避免不必要的拷贝:
1
auto str = getLongString(); // ⓮ 可能触发移动构造
㈦ 典型应用场景
① 迭代器类型简化
1
for(auto it = v.begin(); it != v.end(); ++it) // ⓯
② 模板元编程辅助
1
template<typename T>
2
auto process(T val) -> decltype(val.foo()) { // ⓰
3
return val.foo();
4
}
③ 复杂类型缩写
1
auto callback = std::make_unique<MyCallback>(); // ⓱
㈧ 版本演进
C++标准 | 新增能力 |
---|---|
C++11 | 基本变量类型推导 |
C++14 | 函数返回类型推导、泛型lambda |
C++17 | 结构化绑定、if初始化 |
C++20 | 范围for支持初始化 |