C++威力强大的助手 --- const
Welcome to 9ilk's Code World

(๑•́ ₃ •̀๑) 个人主页: 9ilk
(๑•́ ₃ •̀๑) 文章专栏: C++之旅
const是个奇妙且非比寻常的东西,博主从《Effective C++》一书中认识到关于const更深层次的理解,写此博客进行巩固。
🏠 const的作用
- const可以指定一个“不该被改动的对象”,编译器会强制实施这个约束
- const可修饰类外的作用域(全局域,命名空间域等)中的常量,文件,函数或静态常量等
- const可修饰类内的static和non-static成员
🏠 const修饰指针和迭代器
📌 const修饰指针
const修饰指针无外乎三种:
char greet[] = "hello";
char* pg = greet;//指针指向内容不可变
const char * pg = greet;
char const * pg = greet;//指针本身不可变
char * const pg = greet;//指针本身和指针执行内容都不可变
const char * const pg = greet;
总结:
1.const出现在*号左边时,表示指针指向的内容是常量。
2.const出现在*号右边时,表示指针本身是常量。
3.const出现在*号左右边时,表示指针本身和指针指向的内容都是常量
📌 const与迭代器
- 声明迭代器为const
我们把迭代器看作一个类型,它的作用就像个T*的指针,当声明迭代器为const时,类比const int是int这个int类型变量不可能,此时说明迭代器类型变量是不能变的,也就是类比修饰一个T* const的指针。
vector<int> v = {4,1,2,9,10};
const vector<int>::iterator it = v.begin();it++; //错误,迭代器类型对象不可变
(*it)++; //正确,指向内容可以变
我们也可以利用下面代码进行验证,当生成解决方案时会对其进行报错:
template<class T>
void fun()
{const T x;cout << typeid(x).name() << endl;x++;
}
int main()
{//op o;//cout << o[1];vector<int> v = {3,5};vector<int>::iterator it = v.begin();;fun<vector<int>::iterator>();return 0;
}
- const迭代器
如果你希望迭代器所指的东西不可被改动(也就是类似希望模拟个const T*指针),你需要的是const_iterator.
std::vector<int> v = {1,5,2,3,4};std::vector<int>::const_iterator it = v.begin();*it = 10; //错误,此时是const迭代器,指向内容不可改变。
it++; //此时不是声明迭代器为const,本身迭代器可以改变。
注:我们平时所说的const迭代器就是const_iterator,请注意区分与前者声明迭代器为const进行区分。
🏠 const与函数
📌 const与函数参数
建议:如果对于局部对象或对于函数参数没有改动的需求时,建议将他们声明为const,此时可以避免不必要的麻烦。比如:将“==”键值的“=”。
📌const与函数返回值
- 函数返回一个常量,往往可以降低因客户错误而造成的意外,而且具有安全性和高效性
假设有这样的一个有理数类:
class Rational;const Rational operator*(const Rational& r1,const Rational& r2)
{//...};Rational a,b,c;
...
(a*b) = c;
由于是有理数类,客户可能会将乘积再做一次赋值,此时将operator*的返回值类型设置为const就可以避免这样无意义的赋值动作。
🏠 const与成员函数
📌 const成员函数的好处
1. const成员函数易使class接口比较容易被理解,清楚知道哪个函数可以改动对象内容而哪个函数不行。
2. 有了const成员函数,const对象就能被“操作”,因为const对象只能调用const成员函数;能操作const对象,就能利用传引用(const 类类型 &)提高效率。
- const成员函数与普通成员函数的区别
我们知道普通成员函数参数都有一个隐含的this指针,是不能修改的,也就是类 * const this;而const成员函数的this指针,类型是const 类 * const this,也就是说此时对象的内容也不能被修改。
class Date
{
public:
//... const char& operator[](size_t position)const //operator[]for const对象{return _date[position];}char& operator[](size_t position) //operator[]for non-const 对象{return _date[position];}private:string _date;};int main()
{Date d1("2024/08/04");cout << d1[0] << endl; //调用的是non-const版本const Date d2("2024/08/04")cout << d2[0]; //调用的是const版本return 0;
}
- 说明
1. 两成员函数如果只是常量性不同,也是可以被重载的。因为两个版本隐含的this类型不同,同时
返回值类型也跟着不同。
2.const对象d2的对象指针为const Date* ,更匹配const版本的operator[],因此调用const版本;
而非const对象d1的对象指针为Date*,更匹配非const版本。
📌 bitwise const VS logical const
到这里,我们思考一下什么成员函数如果是const意味着什么?目前有以下两个流行概念需要向大家介绍一下:
- bitwise constness
这种观点的人认为,成员函数只有在不改变对象之任何成员变量时才可以说是const,也就是说不改变对象内的任何一个bit。这种论点的好处是很容易找到违反点:只需找到对成员变量的赋值动作即可。
这种观点正是C++对常量性的定义,因此const成员函数不可以更改对象内任何非静态成员变量。
如果只有指针(而非所指向内容)隶属于对象,(比如有这样的一个类,将数据存储于char*而不是string),不修改char*而修改char*指向内容,此时编译器是认为是bitwise constness的,可以正常通过编译。
class Block
{
public:Block( char* ch ):pText(ch){}char& operator[](size_t position)const{return pText[position];}private:char* pText;
};int main()
{char arr[] = "hello";char* ch = arr;const Block cctb(ch);char* pc = &cctb[0];*pc = 's';return 0;
}
此时可以通过这个漏洞修改成员变量指针指向的内容而不违法const
(注:如果成员变量是string,由于operator[]需要访问pText成员变量,并且你需要保证Block对象的状态不被修改,所以pText的operator[]调用也必须是const的,因此不会出现上述漏洞。)
这种情况导出所谓的logical constness.
- logical constness
class BigArray
{vector<int> v; int accessCounter;
public:int getItem(int index) const { accessCounter++;return v[index];}
};
此类提供了一个
getItem接口,除此之外,为了计算外部访问数组的次数,该类还设置了一个计数器accessCounter,可以看到用户每次调用getItem接口,accessCounter就会自增,很明显,这里的成员v是核心成员,而accessCounter是非核心成员。
我们希望接口 getItem 不会修改核心成员,而不考虑非核心成员是否被修改,此时 getItem 所具备的 const 特性就被称为 logic constness。
问题:在这个函数中虽然accesCounter修改对对象而言可以被接受,但是编译器只认bitwise constness不允许修改怎么办?
- mutable
mutable是C++中一个与const相关的摆动场,他可以释放掉non-static成员变量的bitwise constness约束。
class BigArray {vector<int> v; mutable int accessCounter; //像这样的成员变量可能总是会被更改。
public:int getItem(int index) const { accessCounter++;return v[index];}
};
总结:当const成员函数接受某些修改之后不改变成员函数逻辑状态的成员变量时,这时可以使用mutable来释放const约束。但注意mutable可能会违反对象的不变性,需要慎用。
📌 在const和non-const成员函数中避免重复
对于“bitwise constness”非我所欲的问题,mutable是个解决办法,但并不能解决所有的难题。假设有个类,类内的operator[ ]不单只是返回一个引用指向某字符,也执行边界检验,志记访问信息,甚至可能进行数据完善性检验等...把所有这些放进const版本和非const版本的operator[ 里的问题是会导致代码膨胀以及大量代码重复:
class Text
{public:char& operator[](size_t pos){//... 边界检验//... 志记数据访问//... 检验数据完整性return text[pos];}const char& operator[](size_t pos)const{//... 边界检验//... 志记数据访问//... 检验数据完整性return text[pos];}private:string text;};
避免代码重复的安全做法:
class Text
{public:const char& operator[](size_t pos){//... 边界检验//... 志记数据访问//... 检验数据完整性return text[pos];}char& operator[](size_t pos)const{return (char&)(((const Text &)(*this))[pos]);}private:string text;};
- 说明
1. 这份代码进行了两次转型实现了了“运用const成员函数实现其non-const兄弟”,避免了代码重
复。
2.第一次转型将(*this)也就是这个对象类型强转为const Text&是为了匹配const版本调用const版
本的operator[ ],否则会陷入无限调用非const版本;第二次转型则是用来从const operator[ ]的
返回值中移除const,这其中并未有权限放大的问题,强转是可行的。
3. 反向调用也就是“令const版本调用non-const版本以避免代码重复”是一件错误的事,因为non-
const并未承诺绝不改变其对象的逻辑状态,因此这种做法可能使得对象被改动,当然编译器也不
允许const调用非const,也是一种权限的放大。
总结:
1. 将某些东西声明为const可帮助编译器侦测出错误用法,比如错误的赋值行为使得不必要的对象改动。
2.const可施加于任何作用域的对象,函数参数,函数返回值,成员函数。
3.如果在const成员函数内想改变非核心成员变量以达目的,可利用mutable解除const约束。
4.当const与非const成员函数实质有着等价的实现且代码有大量重复时,可考虑复用const版本以实现非const版本。
相关文章:
C++威力强大的助手 --- const
Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏: C之旅 const是个奇妙且非比寻常的东西,博主从《Effective C》一书中认识到关于const更深层次的理解,写此博客进行巩固。 &#x…...
测试环境搭建整套大数据系统(十八:ubuntu镜像源进行更新)
镜像源更新为清华源 报错显示 解决方案 做好备份 cp /etc/apt/sources.list /etc/apt/sources.list.bak查看配置信息 sudo vim /etc/apt/sources.listsudo sed -i s/cn.archive.ubuntu.com/mirrors.aliyun.com/g /etc/apt/sources.list sudo apt update...
第128天:内网安全-横向移动IPCATSC 命令Impacket 套件CS 插件全自动
环境部署 案例一: 域横向移动-IPC-命令版-at&schtasks 首先是通过外网web访问到win2008,获得了win2008的权限,这一步不做演示 因为里面的主机都不出网,所以只能利用win2008进行正向或者反向连接 信息收集 域内用户信息&…...
记录一次学习过程(msf、cs的使用、横向渗透等等)
目录 用python搭建一个简单的web服务器 代码解释 MSF msfvenom 功能 用途 查看payloads列表 msfconsole 功能 用途 msfvenom和msfconsole配合使用 来个例子 msf会话中用到的一些命令 在windows中net user用法 列出所有用户账户 显示单个用户账户信息 创建用户账…...
C#中DataTable新增列、删除列、更改列名、交换列位置
C#中DataTable新增列、删除列、更改列名、交换列位置 一、新增列 1.1、新增列 /*新增列*/ dataTable.Columns.Add("列名称", Type.GetType("数据类型")); /*比如添加【name】列,string类型的内容*/ dataTable.Columns.Add("name&…...
C#编写多导联扫描式的波形图Demo
本代码调用ZedGraph绘图框架,自己先安装好ZedGraph环境,然后拖一个zedGraphControl控件就行了,直接黏贴下面代码 基本代码显示 using System; using System.Windows.Forms; using ZedGraph; using System.Timers;namespace ECGPlot {public…...
QT网络编程
Qt 给用户提供了网络编程的接口,包括TCP、UDP、HTTP三种协议的API以及各种类,可以了解一下。 而在 QT 中想要使用网络编程,必须在pro文件中添加 network 模块,否则无法包含网络编程所需的头文件。 UDP UDP是传输层的协议&#…...
Django ASGI服务
1. ASGI简介 在Django中, ASGI(Asynchronous Server Gateway Interface)的引入使得Django应用能够支持异步编程. 从Django 3.0开始, Django就增加了对ASGI的支持, 但直到Django 3.1才正式推荐在生产环境中使用ASGI. ASGI是一个用于Python的异步Web服务器的标准接口, 它允许你运…...
Servlet(2)
1、WebServlet 这个注解可以用来修饰一个Servlet类,可以简化配置,替代Web.xml中 的servlet配置 ①value属性 表示指定某个url-pattern ②urlPatterns属性 表示接受多个不同的url-pattern,多个值写在一对{}中,逗号分隔 补充;url-pattern…...
电竞玩家的云端盛宴!四大云电脑平台:ToDesk、顺网云、青椒云、极云普惠云实测大比拼
本文目录 一、云电脑概念及市场需求二、云电竞性能测试2.1 ToDesk云电脑2.2 顺网云2.3 青椒云2.4 极云普惠云电脑 三、四大云电脑平台综合配置对比3.1 CPU处理器3.2 GPU显卡3.3 内存 四、总结 一、云电脑概念及市场需求 在数字化时代的推动下,云计算技术日益成熟&a…...
基础复习(反射、注解、动态代理)
反射 反射,指的是加载类的字节码到内存,并以编程的方法解刨出类中的各个成分(成员变量、方法、构造器等)。 1.获取类的字节码 (3种方式) public class Test1Class{public static void main(String[] arg…...
OGG同步目标端中文乱码处理
现象说明: 源端字符集:AMERICAN_AMERICA.ZHS16GBK 目标端字符集:AMERICAN_AMERICA.AL32UTF8 源端同步过来的数据显示中文乱码。 查询数据库表中含有乱码的字段: select * from xx.xxxx a where to_char(a.crtopetime,yyyy-mm-…...
使用WPF调用Python进行图像灰度处理
1. 前言 在本文中,我们将通过WPF应用程序调用Python脚本进行图像灰度处理。我们将使用Python的OpenCV库来处理图像,并将其转换为灰度图像,然后通过WPF界面来启动Python进程并展示结果。 2. 准备工作 在开始之前,请确保系统已经…...
(二)测试工具
16. 如何进行浏览器兼容性测试? 正确回答通过率:38.0%[ 详情 ] 推荐指数: ★★★★★ 试题难度: 高难 1、兼容性测试含义 兼容性测试是指要测试的软件在不同的硬件平台上、不同的应用软件之间、不同的操作系统中、不同的网络环境中是否可以正常的运行、有无异常的测试过程…...
springboot 博客交流平台-计算机毕业设计源码56406
摘要 博客交流平台 作为一种重要的网络平台,为用户提供了展示自我、分享经验和与他人互动的空间。在国内外,研究者们关注博客交流平台 的各个方面,并取得了显著的进展。研究内容主要包括用户体验和界面设计、社交化和互动性、多媒体内容支持、…...
从0开始搭建vue + flask 旅游景点数据分析系统( 八):美化前端可视化图形
这一期来美化我们仅有的三个可视化图形(可怜),毕竟,帅是一辈子的事。 1 折线图改面积图(渐变色) 需求:折线图改为蓝色的面积图,并且有一点的渐变色。 这个非常简单,只…...
【前端面试】七、算法-迭代器和生成器
目录 1.迭代器 2.生成器 1.迭代器 lterator:也被称作游标Cursor,是一种设计模式。迭代器提供了一种遍历内容的方法(比如 JS 迭代器中的next),而不需要关心内部构造。 // 迭代器的遍历const s new Set([1,2,3,4,5])const it s.values()//…...
vs+qt一些问题
一直遇到的两个问题,今天解决了 1、 因为前后端分离,前端写完了,后端还在一直修改,但是每次都是单独打开的后端的sln,所以会出现这个,把前端的模块删掉就好了。 2、打开vs项目,很多报错&#…...
基于K8S配置Jenkins主从节点实例
基于K8S配置Jenkins主从节点实例 1.配置Jenkins主节点1.确认 Jenkins Pod 名称2.进入 Jenkins Pod:3.生成SSH密钥对4.将公钥复制到目标节点: 2.配置Jenkins的node1节点1.安装java2.配置 Jenkins node1节点的 Java 路径1.添加Java环境变量2.生效Java环境变…...
萱仔环境记录——git的安装流程
最近由于我有一个大模型的offer,由于我只在实验室的电脑上装了git,我准备在自己的笔记本上本地安装一个git,也给我的一个师弟讲解一下git安装和使用的过程,给我的环境安装章节添砖加瓦。 github是基于git的一个仓库托管平台。 g…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
区块链技术概述
区块链技术是一种去中心化、分布式账本技术,通过密码学、共识机制和智能合约等核心组件,实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点:数据存储在网络中的多个节点(计算机),而非…...
