找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2344

积分

0

好友

342

主题
发表于 昨天 03:51 | 查看: 4| 回复: 0

一、核心概念与用法

1. const(常量)

const 是 C++ 中历史悠久的关键字,其核心作用是修饰变量、对象或函数,声明其具有“只读”属性。关键在于,它保证的是“不可修改”,但并不强制该值必须在编译期就确定下来。

核心特点:

  • 修饰变量:变量一旦初始化后,其值便不能被修改。但这个初始化操作可以发生在运行时。
  • 修饰函数:在类成员函数中使用时,表明该函数不会修改类的任何成员变量(mutable 修饰的变量除外)。
  • 修饰指针/引用:这是一个易错点,需要仔细区分“指向常量的指针”和“常量指针”。

代码示例:

#include <iostream>
using namespace std;

int get_num() { return 10; }

int main() {
    // 1. 运行时初始化的 const 变量(只读,但不是编译期常量)
    const int a = get_num(); // 合法,a是只读的,但其值在运行时才确定
    // a = 20; // 错误:const 变量不可修改

    // 2. 编译期初始化的 const 变量(此时可作为编译期常量使用)
    const int b = 20;
    int arr[b]; // 合法(C++11 之后),b 是一个编译期已知的常量

    // 3. 类成员函数中的 const
    class Test {
    public:
        int x = 5;
        int get_x() const { // const 成员函数:承诺不修改成员变量
            // x = 10; // 错误:不能在 const 成员函数中修改成员
            return x;
        }
    };

    return 0;
}

从上面的例子可以看出,const 更多地是一种访问权限的限制,是 C/C++ 编程中保证数据不被意外修改的基础工具。

2. constexpr(常量表达式)

C++11 引入了 constexpr,其核心作用是强制表达式必须在编译期完成求值。你可以将它理解为 const 的“强化版”,专门用于定义编译期常量。

核心特点:

  • 修饰变量:变量的值必须在编译期就能确定,因此可以直接用作数组大小、模板参数等需要编译期常量的地方。
  • 修饰函数:函数可以在编译期被调用并计算返回值(需满足一定条件:参数是常量表达式、函数体足够简单等)。
  • C++14 放宽限制constexpr 函数内部可以包含局部变量、循环和条件判断等更复杂的逻辑。

代码示例:

#include <iostream>
using namespace std;

// constexpr 函数:用于编译期计算
constexpr int add(int a, int b) {
    return a + b;
}

// C++14 风格:constexpr 函数支持更复杂的逻辑
constexpr int factorial(int n) {
    int res = 1;
    for (int i = 1; i <= n; ++i) {
        res *= i;
    }
    return res;
}

int main() {
    // 1. constexpr 变量:值在编译期确定
    constexpr int c = add(10, 20); // c = 30,在编译时计算完成
    int arr[c]; // 合法,c是确凿的编译期常量

    // 2. 错误示例:constexpr 变量必须用编译期已知的值初始化
    // int d = 10;
    // constexpr int e = d; // 错误:d 是运行时变量,值不确定

    // 3. 使用 constexpr 函数进行编译期计算
    constexpr int f = factorial(5); // f = 120,编译期计算
    return 0;
}

constexpr 将“常量”的概念从“只读”提升到了“编译期可知”,是进行编译期计算、优化性能的利器。

3. consteval(立即函数)

C++20 带来了 consteval,它是 constexpr 的“严格版”,核心作用是强制函数必须在编译期执行,绝对不允许在运行时被调用

核心特点:

  • 仅限编译期consteval 函数的调用结果必须是一个编译期常量。任何试图用运行时参数调用它的行为都会导致编译错误。
  • 比 constexpr 更严格constexpr 函数是“可以在编译期执行”,而 consteval 函数是“必须在编译期执行”。

代码示例:

#include <iostream>
using namespace std;

// consteval 函数:强制编译期执行
consteval int square(int n) {
    return n * n;
}

int main() {
    // 合法:使用字面量调用,在编译期计算
    constexpr int g = square(5); // g = 25

    // 错误示例:不能用运行时变量调用 consteval 函数
    int h = 5;
    // int i = square(h); // 错误:h 是运行时变量,无法满足“立即执行”的要求
    return 0;
}

当你需要确保某个函数逻辑(如数学运算、配置生成)百分百在编译期完成,以避免任何运行时开销时,consteval 是你的不二之选。

4. constinit(常量初始化)

同样是 C++20 的新关键字,constinit 的核心作用是强制静态或线程局部变量在编译期进行初始化,但它并不限制变量初始化后的可修改性。

核心特点:

  • 解决初始化顺序问题:专门用于修饰 staticthread_local 变量,确保其初始化发生在编译期或链接期,从而避免令人头疼的“静态初始化顺序错乱”问题。
  • 变量可修改:与 constconstexpr 不同,constinit 只关心初始化时机,不施加“只读”约束,变量之后仍然可以被修改。

代码示例:

#include <iostream>
using namespace std;

// constinit 修饰静态变量:保证编译期初始化,但变量可修改
constinit static int j = 100;

int main() {
    j = 200; // 合法:constinit 只保证初始化时机,不限制修改
    cout << j << endl; // 输出 200

    // 错误示例:constinit 只能用于静态或线程局部存储期的变量
    // constinit int k = 5; // 错误:k 是自动存储期(非static)
    return 0;
}

constinit 是管理程序启动阶段和线程启动阶段变量初始化的强大工具,它保证了初始化的确定性,同时保留了后续修改的灵活性。

二、关键区别对比

关键字 核心作用 是否只读 是否编译期求值 主要适用范围
const 声明只读(值可在运行时确定) 不一定 变量、函数、指针、引用
constexpr 强制编译期求值(常量表达式) 变量、函数、构造函数
consteval 强制函数仅编译期执行(立即函数) 必须 函数
constinit 强制静态变量编译期初始化(但可修改) static / thread_local 变量

总结

  1. const:基础中的基础,核心是“只读保护”。它不关心值何时确定,只关心值一旦确定就不能改。
  2. constexpr:核心是“编译期常量”。它要求值必须在编译期就计算好,是进行编译期计算和优化的关键。
  3. consteval:C++20 的强化武器,核心是“函数必须编译期执行”。它比 constexpr 函数更严格,彻底杜绝运行时调用。
  4. constinit:C++20 的秩序维护者,核心是“静态变量编译期初始化”。它解决了初始化顺序的顽疾,但不限制变量后续的可变性。

简单记忆口诀

  • 想要只读const
  • 想要编译期常量constexpr
  • 想要函数必须编译期跑consteval
  • 想要静态变量确定初始化(还能改)constinit

希望这篇对比能帮助你清晰地理解这四个容易混淆的关键字。在实际的 C/C++ 项目开发中,根据不同的需求(保护数据、编译期计算、优化性能、确定初始化)选择合适的工具,是写出高效、健壮代码的重要一步。如果你在实践中遇到了具体问题,欢迎来 云栈社区 与其他开发者一起交流探讨。




上一篇:深入解读ZipCache论文:基于显著Token识别的KV Cache混合精度量化技术
下一篇:Java新一代数据访问库dbVisitor:如何用统一API操作MySQL、MongoDB与ES
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-11 14:18 , Processed in 0.193434 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表