const和constexpr
constexpr 和 const 的区别
在 C++ 中,const
和 constexpr
都用于定义常量,但它们的用途和行为有显著区别。
简单来说const可以是运行时变量也可以是编译时变量,而constexpr必须是编译时变量
而数组的大小这种就必须是编译时变量
以下是详细对比:
1. 定义和用途
**
const
**:- 表示变量的值在初始化后不可修改(只读)。
- 可以用于运行时常量或编译时常量,具体取决于初始化方式。
- 适用场景:需要确保变量不被修改,但不一定要求编译时求值。
- 示例:
1
2
3const int x = 10; // 编译时常量
int y = 5;
const int z = y; // 运行时常量(y 的值在运行时确定)
**
constexpr
**:- 表示变量或函数的值或结果必须在编译时可求值。
- 用于定义编译时常量或编译时计算的函数,确保结果在编译阶段确定。
- 适用场景:需要编译时常量(如数组大小、模板参数)或性能敏感的编译时计算。
- 示例:
1
2
3constexpr int x = 10; // 编译时常量
constexpr int square(int n) { return n * n; }
int arr[square(5)]; // square(5) 在编译时求值为 25
2. 初始化要求
**
const
**:- 可以用编译时常量或运行时变量初始化。
- 初始化后不可修改,但初始化时间可以是运行时。
- 示例:
1
2
3int input;
std::cin >> input;
const int value = input; // 运行时初始化
**
constexpr
**:- 必须用编译时可求值的表达式初始化。
- 初始化必须在编译时完成,不能依赖运行时值。
- 示例:
1
2
3
4constexpr int value = 10; // 合法
int input;
std::cin >> input;
constexpr int error = input; // 错误:input 是运行时值
3. 作用范围
**
const
**:- 可以修饰变量、指针、成员函数等,强调不可修改性。
- 作用广泛,不限于编译时场景。
- 示例:
1
2const int* ptr = &x; // 指针指向的值不可修改
void foo() const; // 成员函数不修改对象
**
constexpr
**:- 主要用于变量和函数,强调编译时求值。
- C++11 中仅限简单函数,C++14 及以后支持更复杂逻辑(如循环、条件语句)。
- 示例:
1
2
3
4constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
constexpr int f = factorial(5); // 编译时计算 120
4. 函数中的区别
**
const
**:- 用于成员函数,表示函数不会修改对象状态。
- 不涉及编译时求值。
- 示例:
1
2
3
4
5class MyClass {
int x;
public:
int getX() const { return x; } // 不会修改 x
};
**
constexpr
**:- 用于函数,表示函数的结果可在编译时求值(如果输入是编译时常量)。
- 函数体必须满足编译时求值的约束(如避免运行时操作)。
- 示例:
1
2
3
4constexpr int add(int a, int b) { return a + b; }
constexpr int result = add(3, 4); // 编译时求值为 7
int x = 3, y = 4;
int z = add(x, y); // 运行时调用,仍然合法
5. 存储和性能
**
const
**:const
变量可能占用内存(除非优化为常量折叠)。- 如果是运行时常量,存储在栈或堆上。
- 示例:
1
const int x = std::rand(); // 运行时初始化,占用内存
**
constexpr
**:constexpr
变量通常不占用运行时内存(编译器直接内联常量值)。- 提高性能,因为值在编译时确定。
- 示例:
1
constexpr int x = 10; // 编译时常量,通常不占用内存
6. 兼容性和限制
**
const
**:- C++98 就存在,兼容性强。
- 限制较少,适用于各种场景。
- 不保证编译时求值,不能直接用于模板参数或数组大小。
**
constexpr
**:- C++11 引入,功能在 C++14、C++17 等版本中扩展。
- 限制严格(如函数体需满足编译时求值规则)。
- 可用于模板参数、数组大小等编译时场景。
- 示例:
1
2
3
4constexpr int n = 5;
int arr[n]; // 合法,n 是编译时常量
const int m = 5;
int arr2[m]; // 合法,但依赖编译器优化
总结
特性 | const |
constexpr |
---|---|---|
含义 | 值不可修改 | 编译时可求值 |
初始化 | 可运行时或编译时初始化 | 必须编译时初始化 |
适用场景 | 运行时/编译时常量,成员函数修饰 | 编译时常量,编译时计算函数 |
函数支持 | 成员函数不可修改对象 | 编译时求值函数 |
内存 | 可能占用内存 | 通常不占用内存(内联) |
引入版本 | C++98 | C++11 |
建议
- 需要编译时常量或性能敏感的场景(如模板参数、数组大小),使用
constexpr
。 - 需要运行时常量或只读保护,使用
const
。 - 两者可结合使用,例如:
1
constexpr const int x = 10; // 既是编译时常量,又不可修改
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.
Comments