C++中const与constexpr的区别

news2025/4/22 20:42:14

在C++中,`const`和`constexpr`都用于定义常量,但它们的用途和行为有显著区别:

### 1. **初始化时机**
- **`const`**:表示变量是只读的,但其值可以在**编译时或运行时**初始化。
  ```cpp
  const int a = 5;              // 编译时初始化
  const int b = some_function(); // 运行时初始化(合法)
  ```

- **`constexpr`**:变量必须在**编译时**初始化,且初始化表达式必须是常量。
  ```cpp
  constexpr int c = 5;          // 合法
  constexpr int d = some_function(); // 仅当 some_function() 是 constexpr 函数时合法
  ```

---

### 2. **应用场景**
- **`const`**:用于声明运行时常量,确保值不可修改。
  ```cpp
  int x = 10;
  const int y = x;  // 合法,但 y 的值在运行时确定
  ```

- **`constexpr`**:用于需要编译时常量的场景(如数组大小、模板参数)。
  ```cpp
  constexpr int size = 10;
  int arr[size];  // 合法,size 是编译时常量

  int x = 10;
  constexpr int invalid_size = x; // 错误:x 不是常量表达式
  ```

---

### 3. **函数与对象**
- **`constexpr` 函数**:可以在编译时求值(若参数是常量)。
  ```cpp
  constexpr int square(int x) { return x * x; }
  constexpr int val = square(5); // 编译时计算(val = 25)
  int y = square(10);           // 运行时计算
  ```

- **`const` 成员函数**:表示函数不会修改对象状态,但调用时机不限定于编译时。
  ```cpp
  class MyClass {
  public:
      int getValue() const { return value; } // 运行时调用
  private:
      int value;
  };
  ```

- **`constexpr` 对象**:允许在编译时构造对象。
  ```cpp
  class Point {
  public:
      constexpr Point(int x, int y) : x(x), y(y) {}
      constexpr int getX() const { return x; }
  private:
      int x, y;
  };

  constexpr Point p(3, 4);          // 编译时构造
  constexpr int x = p.getX();       // x = 3(编译时获取值)
  ```

---

### 4. **指针与引用**
- **`const` 指针**:指针本身或指向的值不可修改。
  ```cpp
  const int* ptr1 = &a;  // 指向的值不可变
  int* const ptr2 = &b;  // 指针本身不可变
  ```

- **`constexpr` 指针**:必须指向编译时确定的地址(如全局变量或静态变量)。
  ```cpp
  constexpr int* ptr3 = nullptr; // 合法
  int global = 42;
  constexpr int* ptr4 = &global; // 合法(全局变量地址在编译时确定)
  ```

---

### 总结
| **特性**               | `const`                          | `constexpr`                     |
|------------------------|----------------------------------|---------------------------------|
| **初始化时机**          | 编译时或运行时                   | 必须编译时                      |
| **用途**               | 运行时常量                       | 编译时常量、模板元编程          |
| **函数修饰**           | 表示函数不修改对象状态           | 函数可在编译时求值              |
| **对象构造**           | 运行时构造                       | 允许编译时构造(需 constexpr 构造函数) |
| **指针/引用**          | 可指向动态内存                   | 必须指向编译时确定的地址        |

- **优先使用 `constexpr`**:当需要编译时常量或优化性能时(如数组大小、模板参数)。
- **使用 `const`**:当仅需运行时常量(如函数参数、返回值保护)。

在编程中,「编译时」和「运行时」是两个关键阶段,它们的区别直接影响了代码的行为和结果。以下是它们的核心区别:

---

### **1. 时间与操作**
- **编译时 (Compile Time)**  
  - **时间点**:代码被编译器处理(生成可执行文件前)。  
  - **操作内容**:  
    - 语法检查(如括号是否匹配、变量是否声明)。  
    - 类型检查(如 `int x = "hello"` 会报错)。  
    - 优化(如删除未使用的变量、内联函数)。  
    - 生成机器码或中间代码。  
  - **示例**:  
    ```cpp
    int x = 5;
    std::string s = x; // 编译错误:类型不匹配
    ```

- **运行时 (Runtime)**  
  - **时间点**:程序实际执行时(用户运行可执行文件后)。  
  - **操作内容**:  
    - 内存分配(如 `new` 和 `malloc`)。  
    - 动态逻辑(如用户输入、文件读写)。  
    - 异常处理(如除以零、空指针访问)。  
  - **示例**:  
    ```cpp
    int x = 0;
    std::cin >> x;      // 运行时输入
    int y = 10 / x;     // 运行时可能崩溃(如果 x=0)
    ```

---

### **2. 输入依赖**
- **编译时**:  
  - 所有数据必须是已知的、固定的(如常量表达式)。  
  - 示例:数组大小、模板参数、`constexpr` 值。  
  ```cpp
  constexpr int size = 10;
  int arr[size]; // 合法:size 是编译时常量
  ```

- **运行时**:  
  - 数据可以是动态的(如用户输入、随机数)。  
  ```cpp
  int size;
  std::cin >> size;   // 运行时输入
  int* arr = new int[size]; // 动态内存分配(运行时确定大小)
  ```

---

### **3. 错误类型**
- **编译时错误**:  
  - 由编译器发现(如语法错误、类型不匹配)。  
  - 必须修复后才能生成可执行文件。  
  ```cpp
  int x = "hello"; // 编译错误:类型不匹配
  ```

- **运行时错误**:  
  - 程序执行时发生的错误(如内存泄漏、空指针访问)。  
  - 可能通过测试或异常处理捕获。  
  ```cpp
  int* ptr = nullptr;
  *ptr = 5; // 运行时崩溃(空指针解引用)
  ```

---

### **4. 性能影响**
- **编译时计算**:  
  - 由编译器完成(如 `constexpr` 函数),减少运行时开销。  
  ```cpp
  constexpr int factorial(int n) { return (n <= 1) ? 1 : n * factorial(n-1); }
  constexpr int result = factorial(5); // 编译时计算(result = 120)
  ```

- **运行时计算**:  
  - 在程序执行时完成,可能占用 CPU 和内存资源。  
  ```cpp
  int x = 5;
  int result = 1;
  for (int i = 1; i <= x; i++) { result *= i; } // 运行时计算
  ```

---

### **5. 实际应用场景**
- **编译时需要确定的场景**:  
  - 数组大小、模板参数、`static_assert` 断言。  
  ```cpp
  template <int N>
  struct Array { int data[N]; }; // N 必须是编译时常量
  ```

- **运行时需要处理的场景**:  
  - 用户交互(输入/输出)、网络请求、动态内存分配。  
  ```cpp
  std::string name;
  std::cout << "Enter your name: ";
  std::cin >> name; // 运行时输入
  ```

---

### **总结**
| **特性**         | **编译时**                          | **运行时**                          |
|------------------|-------------------------------------|-------------------------------------|
| **时间点**       | 代码编译阶段                        | 程序执行阶段                        |
| **输入依赖**     | 必须已知(常量)                    | 可以是动态的(变量或用户输入)      |
| **错误类型**     | 语法错误、类型错误                  | 崩溃、内存泄漏、逻辑错误            |
| **性能优化**     | 通过编译时计算减少运行时开销        | 依赖算法和硬件性能                  |
| **典型操作**     | 静态类型检查、模板实例化            | 内存分配、异常处理、I/O 操作        |

---

### **为什么程序员需要关注两者的区别?**
1. **优化性能**:将能提前计算的任务放在编译时(如 `constexpr`)。  
2. **避免错误**:通过编译时检查(如类型安全)减少运行时崩溃风险。  
3. **灵活设计**:区分静态(编译时)和动态(运行时)逻辑,提高代码可维护性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2340329.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决Windows安全中心显示空白页面

1、电脑重装系统后&#xff0c;发现原本一些软件打不开了&#xff0c;电脑莫名认为有病毒&#xff0c;自动删除插件。附图。 2、第一反应是电脑防火墙的原因&#xff0c;默认威胁防护识别到了病毒软件&#xff0c;自动删除。在开始屏幕搜Windows安全中心&#xff0c;打开之后发…

【MQ篇】初识MQ!

目录 一、什么是MQ&#xff1f;简单来说就是个“快递中转站” &#x1f4e6;二、为什么要用MQ&#xff1f;用了它&#xff0c;好处多多&#xff01;&#x1f929;三、MQ的应用场景&#xff1a;各行各业都能用&#xff01;&#x1f30d;四、MQ的优缺点&#xff1a;硬币的两面&am…

2、SpringAI接入ChatGPT与微服务整合

2、SpringAI接入ChatGPT与微服务整合 小薛博客AI 大模型资料 1、SpringAI简介 https://spring.io/projects/spring-ai Spring AI是一个人工智能工程的应用框架。其目标是将Spring生态系统的设计原则&#xff08;如可移植性和模块化设计&#xff09;应用于人工智能领域&#…

榕壹云预约咨询系统:基于ThinkPHP+MySQL+UniApp打造的灵活预约小程序解决方案

数字化咨询场景的痛点与解决方案 在心理咨询、医疗问诊、法律咨询等需要预约服务的场景中&#xff0c;传统线下预约存在效率低、管理复杂、资源分配不均等问题。榕壹云预约咨询系统基于ThinkPHPMySQLUniApp技术栈开发&#xff0c;为咨询类行业提供了一套高效、安全、可扩展的数…

opencv 图像矫正的原理

图像矫正的原理是透视变换&#xff0c;下面来介绍一下透视变换的概念。 听名字有点熟&#xff0c;我们在图像旋转里接触过仿射变换&#xff0c;知道仿射变换是把一个二维坐标系转换到另一个二维坐标系的过程&#xff0c;转换过程坐标点的相对位置和属性不发生变换&#xff0c;…

计算机前沿技术课程论文 K-means算法在图像处理的应用

K-means算法在图像处理的应用 这是本人在计算机前沿技术课程中的课程论文文章&#xff0c;为了方便大家参考学习&#xff0c;我把完整的论文word文档发到了我的资源里&#xff0c;有需要的可以自取。 点击完整资源链接 目录 K-means算法在图像处理的应用摘要&#xff1a;引言1…

WSL2-Ubuntu22.04安装URSim5.21.3

WSL2-Ubuntu22.04安装URSim5.21.3 准备安装启动 准备 名称版本WSL2Ubuntu22.04URSim5.21.3VcXsrvNaN WSL2安装与可视化请见这篇:WSL2-Ubuntu22.04-配置。 安装 我们是wsl2-ubuntu22.04&#xff0c;所以安装Linux版本的URSim&#xff0c;下载之前需要注册一下&#xff0c;即…

blender 录课键位显示插件(图文傻瓜式安装)

1、下载 点击这个链接进行下载https://github.com/nutti/Screencast-Keys 下载好不用解压 2、安装 打开blender进行安装 点击编辑选择偏好设置 选择插件再点击这个下箭头 选择从磁盘安装 然后找到自己刚刚下载好的&#xff0c;点击从磁盘安装 安装完成后勾选上插件 …

天翼云手机断开连接2小时关机

2025-04-21 天翼云手机断开连接2小时自动 天翼云手机 4元1个月 天翼云手机永不关机 天翼云手机不休眠 天翼云手机断开连接时&#xff0c;界面显示&#xff1a;离线运行&#xff0c;2小时后自动关机 电脑每小时自动连接一次 手机每小时自动连接一次

基于 FFmpeg 的音视频处理基础原理与实验探究

目录 1 基本知识1.1 解封装1.2 AAC和ADTS说明 1.3 H2641.3.1 H264编码结构解析1.3.2 NALU1.3.2 分类 2 实验1 探究音视频信息2.1 重要结构体介绍2.2 相关的API 3 实验二 提取AAC数据4 实验三 提取h264 1 基本知识 1.1 解封装 封装的逆向操作&#xff1a;封装是把音频流、视频流…

我用deepseek做了一个提取压缩文件夹下pdf和word文件工具

由于最近需要把大量的压缩文件的pdf和word文件统一复制到一个文件夹中。 我们一般正常操作方式的是把一个压缩文件一个一个解压&#xff0c;然后在把一个的解压好的文件夹下文件复制到另外一个文件夹中。 这个也需太繁琐了&#xff0c;从以往统计的需要花费两个小时间&#x…

机器人进阶---视觉算法(五)仿射变换和投影变换有什么区别

仿射变换和投影变换有什么区别 1. 定义2. 几何特性3. 变换矩阵4. 应用场景5. Python代码示例仿射变换投影变换6. 总结仿射变换和投影变换都是图像处理中常用的几何变换方法,但它们在变换性质、应用场景和变换矩阵等方面存在一些关键区别。 1. 定义 仿射变换 (Affine Transform…

如何在 Amazon EC2 上部署 Java(Spring Boot 版)

让我们学习如何将 Java Spring Boot Web 服务器部署到 Amazon EC2。每月只需 3 美元。 使用 Azure&#xff0c;您可能不知道要花费多少钱。 Spring Boot 项目示例 在本教程中&#xff0c;我们将重点介绍如何将 Java Spring Boot 服务器部署到 Amazon EC2&#xff0c;因此我们不…

IDEA打不开、打开报错

目录 场景异常原因解决 场景 1、本机已经安装了IDEA 2、再次安装另外一个版本的IDEA后打不开、打开报错 异常 这里忘记截图了。。。 原因 情况1-打不开&#xff1a;在同一台电脑安装多个IDEA是需要对idea的配置文件进行调整的&#xff0c;否则打不开 情况2-打开报错&#…

【React】项目的搭建

create-react-app 搭建vite 搭建相关下载 在Vue中搭建项目的步骤&#xff1a;1.首先安装脚手架的环境&#xff0c;2.通过脚手架的指令创建项目 在React中有两种方式去搭建项目&#xff1a;1.和Vue一样&#xff0c;先安装脚手架然后通过脚手架指令搭建&#xff1b;2.npx create-…

CSS例子 > 图片瀑布流布局(vue2)

<template><div class"container"><!-- 临时容器用于计算高度 --><div v-if"!isLayoutReady" class"temp-container"><divv-for"(item, index) in list":key"temp- index":ref"(el) > …

1.2软考系统架构设计师:系统架构的定义与作用 - 练习题附答案及超详细解析

系统架构定义与作用综合知识单选题 题目覆盖核心概念、发展历程、设计原则、评估标准及易混淆点&#xff0c;附答案解析&#xff1a; 1. 系统架构的标准定义源自于以下哪个标准&#xff1f; A. ISO/IEC 9126 B. IEEE 1471-2000 C. TOGAF 9.2 D. ITIL v4 答案&#xff1a;B 简…

关于springmvc的404问题的一种猜测解决方案

本文是记录关于在学习动力结点老杜的springmvc时候遇到的404报错的一种解决方式&#xff1b; 由于本人之前学过老杜的springmvc&#xff0c;且运行成功&#xff0c;当时使用的是tomcat10.1.19版本。 idea使用2023.3.2版本。 而这次进行回顾的时候&#xff0c;使用tomcat10.0.1…

使用Postman调测“获取IAM用户Token”接口实际操作

概述 Postman是网页调试与辅助接口调用的工具&#xff0c;具有界面简洁清晰、操作方便快捷的特性&#xff0c;可以处理用户发送的HTTP请求&#xff0c;例如&#xff1a;GET&#xff0c;PUT、POST&#xff0c;DELETE等&#xff0c;支持用户修改HTTP请求中的参数并返回响应数据。…

如何测试雷达与相机是否时间同步?

在多传感器融合系统中&#xff0c;相机与雷达的协同感知已成为环境理解的关键。相机通过捕捉纹理信息识别物体类别&#xff0c;而雷达利用激光或毫米波实现全天候精确测距。两者的数据融合既能避免单一传感器缺陷&#xff08;如相机受光照影响、雷达缺乏语义信息&#xff09;&a…