第二问:C++中const用法详解

简介: `const` 是 C++ 中用于定义常量的关键字,主要作用是防止值被修改。它可以修饰变量、指针、函数参数、返回值、类成员等,确保数据的不可变性。`const` 的常见用法包括:

第二问:C++中const用法详解

概述

const 是 C++ 中用于定义常量性的重要关键字,其主要作用是防止值被修改。以下是 const 的主要用法及其如何保证不变性的详细说明:

详细说明

1. 修饰变量

定义常量变量后,变量的值在整个作用域中不可修改:

const int a = 10;
// a = 20; // 错误,无法修改 const 变量

原理:

编译器会在编译期检测到对 const 变量的修改,并报错,从而保证变量值不可变。

2. 修饰指针

(1) 指向的内容不可变

const int value = 10;
const int* ptr = &value; // 指针所指向的值不可变
// *ptr = 20; // 错误,无法修改指向的内容

解读:

const int* ptr 表示指针指向的对象是常量,指针自身可以改变指向。

(2) 指针本身不可变

int value = 10;
int value2 = 20;
int* const ptr = &value; // 指针本身不可变
ptr = &value2; // 错误,无法修改指针本身

解读:

int* const ptr 表示指针本身不可变,但指向的内容可以改变。

(3) 指针本身和指向内容都不可变

const int value = 10;
const int* const ptr = &value; // 指针和内容均不可变

解读:

这种用法常用于需要绝对不变的场景,例如安全访问硬件寄存器或配置。

3. 修饰函数参数

(1) 值传递

在函数参数中使用 const,避免对参数值的修改:

void func(const int x) {
   // x = 20; // 错误,无法修改 x
}

(2) 指针参数

void func(const int* ptr) {
   // *ptr = 20; // 错误,无法修改指针所指的值
}

(3) 引用参数

引用传递的参数被修饰为 const,可以避免函数中修改原始值:

void func(const int& ref) {
   // ref = 20; // 错误,无法修改引用的值
}

作用:

  • 防止意外修改参数值。
  • 提高代码的可读性,明确意图。

4. 修饰返回值

(1) 修饰普通返回值

const int func() {
   return 10;
}
// int& x = func(); // 错误,无法绑定非常量引用

作用:

防止函数返回值被错误修改,常用于拷贝返回。

(2) 修饰指针返回值

const int* func() {
   static int value = 10;
   return &value;
}

作用:

保证返回的指针所指内容不可变。

5. 修饰成员函数

(1) 保证成员函数不修改对象状态

class MyClass {
public:
   void show() const {
       // 成员函数中无法修改类成员变量
   }
};

作用:

通过在函数后加 const,确保函数内部不会修改成员变量,也不会调用其他非 const 成员函数。

(2) 配合 mutable 成员变量

const 成员函数中可以修改被 mutable 修饰的成员变量:

class MyClass {
private:
   mutable int count;
public:
   void increment() const {
       count++;
   }
};

6. 修饰类成员

(1) 常量成员变量

必须在类的构造函数初始化列表中初始化:

class MyClass {
private:
   const int value;
public:
   MyClass(int val) : value(val) {}
};

(2) 常量对象

const MyClass obj;
// obj.modify(); // 错误,无法调用非 const 成员函数

作用:

确保常量对象的状态不被修改。

上面列举的是 const 的主要使用场景,但并不是 全部。C++ 中 const 的应用非常广泛,有一些更高级或特定场景的用法,我再补充如下,力求全面覆盖:

7. 修饰模板中的参数

const 可用于模板参数声明中,限制模板参数为常量值:

template <int N>
class Array {
   int data[N]; // 固定大小的数组
};
Array<10> arr; // 模板参数是一个常量

8. 与 constexpr 联合使用

const 可以与 constexpr 配合,用于定义编译期的常量:

constexpr const int MAX_SIZE = 100; // 既是常量,又可用于编译期计算

注意:

  • constexpr 比单独使用 const 更强大,因为它还要求值在编译期就能确定。

9. 在 STL 容器中的应用

在标准库(如 std::vectorstd::map 等)中,const 用法有以下场景:

(1) 常量迭代器

const_iterator 用于保证迭代器指向的内容不可修改:

std::vector<int> vec = {1, 2, 3};
for (std::vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it) {
   // *it = 10; // 错误,无法修改
}

(2) 修饰容器中的元素

可以使用 const 确保容器中的元素不可修改:

std::vector<const int*> vec; // 存储不可修改的指针

10. 修饰右值引用参数(C++11 引入)

const 结合右值引用,主要用于重载函数,防止移动操作修改临时对象:

void func(const int&& x) {
   // x 是一个右值引用,但其值不可被修改
}

右值通常用于临时变量,const 修饰可以保护这些临时变量。

11. 与类的 static 成员变量结合

const 修饰类的静态成员变量,通常用于定义不可改变的类级别常量:

class MyClass {
public:
   static const int MAX_VALUE = 100; // 静态常量成员
};

静态常量成员可以直接在类内初始化,但仅限于整型或枚举类型。非整型必须在类外定义并初始化。

12. 修饰位域(bit-field)成员

位域是 C++ 中处理结构体的低级特性,const 可以保护位域成员:

struct Flags {
   const unsigned int flag1 : 1; // 常量位域
   unsigned int flag2 : 2;
};

13. 修饰捕获变量(C++11 Lambda 表达式)

在 Lambda 捕获列表中,const 可以确保捕获的变量不可修改:

int x = 10;
auto lambda = [x]() mutable {
   // x = 20; // 如果未加 `mutable`,默认 x 是 const
};

如果没有 mutable 修饰,捕获的变量是不可修改的,默认按 const 值传递。

14. const 在函数指针和函数对象中的应用

(1) 修饰函数指针

函数指针的常量性可以通过 const 限定:

void func() {}
void (*const funcPtr)() = func; // funcPtr 指向的函数不可改变

(2) 修饰返回函数对象

如果函数返回的是一个 const 对象,可以保护返回值不被修改:

const std::function<void()> getFunc() {
   return []() { /* Do something */ };
}

15. 修饰数组

在数组中,const 可以保护整个数组内容不被修改:

const int arr[] = {1, 2, 3};
// arr[0] = 10; // 错误,无法修改数组内容

16. const 在多线程中的作用

在多线程中,const 变量是线程安全的,因为它们不会被修改,避免了数据竞争(data race):

const int threadCount = 4; // 多线程间安全共享的常量

17. 修饰 union 成员(特殊场景)

C++ 中 union 的成员通常不允许是 const,但如果 union 的成员是对象,则可以间接地包含 const 成员:

union MyUnion {
   const int value; // 在特殊情况下可能需要使用
};

18. 在函数重载与模板匹配中的特殊用法

const 修饰的函数或模板可以区分重载:

void func(int x) {
   // 普通版本
}
void func(const int x) {
   // 常量版本
}

19. 与 volatile 联合使用

constvolatile 联合使用时,表示变量的值不能被程序修改,但可能会被硬件或外部事件改变:

const volatile int reg = 0x1234; // 例如硬件寄存器

典型场景:

  • 嵌入式开发中保护硬件寄存器的值。

20. 修饰非类型模板参数

在模板中,非类型参数可以使用 const 修饰:

template <const int N>
class Matrix {
   int data[N][N];
};
Matrix<4> m; // 矩阵大小固定为 4x4

用法分类

总结

const 保证不变性的原理可以概括为以下三点:

  1. 编译时检测:编译器在编译阶段检查 const 的限制条件,禁止对 const 数据的非法操作。
  2. 内存保护:在某些平台上(例如嵌入式系统),const 数据可能会放在只读存储区,防止运行时修改。
  3. 限定作用域:通过 const 明确表达代码意图,减少因误修改引起的错误。

C++ 的 const 用法极其广泛,涵盖变量、指针、数组、函数、类成员、模板、Lambda 表达式等多个方面。从编译时检查到运行时保护,const 在提高程序安全性、可读性和优化性能方面扮演了重要角色,正确使用 const 可以提高代码的安全性和可读性,是现代 C++ 编程中非常重要的实践。

如果还有更特殊的应用场景,欢迎探讨!

目录
相关文章
|
6天前
|
存储 运维 安全
云上金融量化策略回测方案与最佳实践
2024年11月29日,阿里云在上海举办金融量化策略回测Workshop,汇聚多位行业专家,围绕量化投资的最佳实践、数据隐私安全、量化策略回测方案等议题进行深入探讨。活动特别设计了动手实践环节,帮助参会者亲身体验阿里云产品功能,涵盖EHPC量化回测和Argo Workflows量化回测两大主题,旨在提升量化投研效率与安全性。
云上金融量化策略回测方案与最佳实践
|
8天前
|
人工智能 自然语言处理 前端开发
从0开始打造一款APP:前端+搭建本机服务,定制暖冬卫衣先到先得
通义灵码携手科技博主@玺哥超carry 打造全网第一个完整的、面向普通人的自然语言编程教程。完全使用 AI,再配合简单易懂的方法,只要你会打字,就能真正做出一个完整的应用。
8203 19
|
12天前
|
Cloud Native Apache 流计算
资料合集|Flink Forward Asia 2024 上海站
Apache Flink 年度技术盛会聚焦“回顾过去,展望未来”,涵盖流式湖仓、流批一体、Data+AI 等八大核心议题,近百家厂商参与,深入探讨前沿技术发展。小松鼠为大家整理了 FFA 2024 演讲 PPT ,可在线阅读和下载。
4436 10
资料合集|Flink Forward Asia 2024 上海站
|
20天前
|
人工智能 自动驾驶 大数据
预告 | 阿里云邀您参加2024中国生成式AI大会上海站,马上报名
大会以“智能跃进 创造无限”为主题,设置主会场峰会、分会场研讨会及展览区,聚焦大模型、AI Infra等热点议题。阿里云智算集群产品解决方案负责人丛培岩将出席并发表《高性能智算集群设计思考与实践》主题演讲。观众报名现已开放。
|
12天前
|
自然语言处理 数据可视化 API
Qwen系列模型+GraphRAG/LightRAG/Kotaemon从0开始构建中医方剂大模型知识图谱问答
本文详细记录了作者在短时间内尝试构建中医药知识图谱的过程,涵盖了GraphRAG、LightRAG和Kotaemon三种图RAG架构的对比与应用。通过实际操作,作者不仅展示了如何利用这些工具构建知识图谱,还指出了每种工具的优势和局限性。尽管初步构建的知识图谱在数据处理、实体识别和关系抽取等方面存在不足,但为后续的优化和改进提供了宝贵的经验和方向。此外,文章强调了知识图谱构建不仅仅是技术问题,还需要深入整合领域知识和满足用户需求,体现了跨学科合作的重要性。
|
8天前
|
人工智能 容器
三句话开发一个刮刮乐小游戏!暖ta一整个冬天!
本文介绍了如何利用千问开发一款情侣刮刮乐小游戏,通过三步简单指令实现从单个功能到整体框架,再到多端优化的过程,旨在为生活增添乐趣,促进情感交流。在线体验地址已提供,鼓励读者动手尝试,探索编程与AI结合的无限可能。
三句话开发一个刮刮乐小游戏!暖ta一整个冬天!
|
1月前
|
存储 人工智能 弹性计算
阿里云弹性计算_加速计算专场精华概览 | 2024云栖大会回顾
2024年9月19-21日,2024云栖大会在杭州云栖小镇举行,阿里云智能集团资深技术专家、异构计算产品技术负责人王超等多位产品、技术专家,共同带来了题为《AI Infra的前沿技术与应用实践》的专场session。本次专场重点介绍了阿里云AI Infra 产品架构与技术能力,及用户如何使用阿里云灵骏产品进行AI大模型开发、训练和应用。围绕当下大模型训练和推理的技术难点,专家们分享了如何在阿里云上实现稳定、高效、经济的大模型训练,并通过多个客户案例展示了云上大模型训练的显著优势。
104585 10
|
7天前
|
消息中间件 人工智能 运维
12月更文特别场——寻找用云高手,分享云&AI实践
我们寻找你,用云高手,欢迎分享你的真知灼见!
650 40
|
5天前
|
弹性计算 运维 监控
阿里云云服务诊断工具:合作伙伴架构师的深度洞察与优化建议
作为阿里云的合作伙伴架构师,我深入体验了其云服务诊断工具,该工具通过实时监控与历史趋势分析,自动化检查并提供详细的诊断报告,极大提升了运维效率和系统稳定性,特别在处理ECS实例资源不可用等问题时表现突出。此外,它支持预防性维护,帮助识别潜在问题,减少业务中断。尽管如此,仍建议增强诊断效能、扩大云产品覆盖范围、提供自定义诊断选项、加强教育与培训资源、集成第三方工具,以进一步提升用户体验。
632 243
|
2天前
|
弹性计算 运维 监控
云服务测评 | 基于云服务诊断全方位监管云产品
本文介绍了阿里云的云服务诊断功能,包括健康状态和诊断两大核心功能。作者通过个人账号体验了该服务,指出其在监控云资源状态和快速排查异常方面的优势,同时也提出了一些改进建议,如增加告警配置入口和扩大诊断范围等。