✅ C++ 中的 const
关键字 学习笔记
💡 关键词:常量、编译时常量、性能优化、安全性、C++11/C++14/C++17/C++20 特性
🧠 一、const
—— 常量修饰符
1.1 定义
const
是 “constant” 的缩写。- 表示一个变量一旦被初始化,其值就不能再改变。
1.2 基本用法
const int max_value = 100;
max_value = 200; // ❌ 编译错误
1.3 const
修饰指针
写法 | 含义 |
---|---|
const int* p 或 int const* p |
指向的内容不可变 |
int* const p |
指针本身不可变 |
const int* const p |
指针和内容都不可变 |
int a = 5, b = 10;
const int* p1 = &a;
p1 = &b; // ✅ OK:可以修改指针指向
// *p1 = 20; // ❌ 错误:不能修改指向的内容
int* const p2 = &a;
*p2 = 15; // ✅ OK:可以修改指向的内容
// p2 = &b; // ❌ 错误:不能修改指针指向
const int* const p3 = &a;
// *p3 = 20; // ❌ 错误
// p3 = &b; // ❌ 错误
1.4 成员函数后加 const
表示该成员函数不会修改类的成员变量。
class Rectangle {
public:
Rectangle(int w, int h) : width(w), height(h) {}
int area() const {
return width * height;
}
private:
int width, height;
};
⚠️ 注意:非
const
函数不能在const
对象上调用。
🔥 二、constexpr
—— 编译期常量表达式
2.1 定义
- 表示这个变量或函数的结果可以在编译时求值,并且结果是一个常量。
2.2 基本用法
constexpr int square(int x) {
return x * x;
}
constexpr int s = square(5); // ✅ 编译时计算成 25
char buffer[s]; // ✅ 合法,数组大小为 25
2.3 constexpr
变量
constexpr double pi = 3.141592653589793;
- 必须在编译时就能确定值。
- 可用于数组大小、模板参数等需要常量表达式的场合。
2.4 constexpr
函数
constexpr int factorial(int n) {
int result = 1;
for (int i = 2; i <= n; ++i)
result *= i;
return result;
}
- C++14 起支持复杂逻辑(如循环、条件判断)。
2.5 if constexpr
(C++17)
template <typename T>
void foo(T t) {
if constexpr (std::is_integral_v<T>) {
// 编译时选择路径
} else {
// 其他处理方式
}
}
⚡ 三、consteval
—— 立即函数(Immediate Function)
3.1 定义
consteval
是 C++20 新增的关键字。- 表示这个函数必须在编译期求值,否则会报错!
3.2 示例
consteval int sqr(int x) {
return x * x;
}
int main() {
constexpr int a = sqr(5); // ✅ OK:编译时求值
int b = 5;
int c = sqr(b); // ❌ 错误:b 是运行时变量
}
🛠️ 四、constinit
—— 静态初始化保证
4.1 定义
constinit
是 C++20 新增的关键字。- 用于确保变量具有静态初始化(不是运行时动态初始化),避免不确定性行为。
4.2 示例
constinit int val = 100; // ✅ OK:静态初始化
int get_value() {
return 42;
}
constinit int value = get_value(); // ❌ 错误:get_value() 不是常量表达式
📊 五、四个关键字对比表
特性 | const |
constexpr |
consteval |
constinit |
---|---|---|---|---|
是否修饰变量 | ✅ | ✅ | ❌(仅函数) | ✅ |
是否修饰函数 | ❌ | ✅ | ✅ | ❌ |
是否必须编译时求值? | ❌ | 否(推荐) | ✅ | 否(但必须是常量表达式) |
是否影响运行时性能? | 否 | 是(提前计算) | 是(强制编译期) | 否(但提升可预测性) |
是否可用于数组大小、模板参数? | 否 | ✅ | ✅ | ✅ |
是否能用于 if 条件分支? |
❌ | ✅ | ✅ | ❌ |
🧩 六、推荐实践
场景 | 推荐使用 |
---|---|
定义数学常量 | ✅ constexpr |
定义配置参数 | ✅ const 或 constexpr |
强制编译期计算 | ✅ consteval |
保证静态初始化 | ✅ constinit |
函数参数传入只读数据 | ✅ const 引用 |
数组大小、模板参数 | ✅ constexpr |
📝 七、总结一句话
const
是“我不会改这个值”constexpr
是“这个值编译时就确定了”consteval
是“你必须在编译时算出来”constinit
是“我要在程序启动时就准备好”
📘 示例汇总
// const 基础
const int a = 10;
// constexpr 基础
constexpr int b = 10;
constexpr int c = b * 2; // ✅ OK
// constexpr 函数
constexpr int add(int x, int y) {
return x + y;
}
constexpr int d = add(3, 4); // ✅ 编译时计算成 7
// consteval 函数
consteval int cube(int x) {
return x * x * x;
}
constexpr int e = cube(3); // ✅ OK
int f = 3;
cube(f); // ❌ 错误:f 是运行时变量
// constinit 变量
constinit int global_val = 100; // ✅ OK
constinit int another_val = add(2, 3); // ✅ OK