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…...

品味食家巷蛋奶酪饼,感受西北美食魅力
在广袤的西北大地,美食的丰富多样令人叹为观止。而食家巷蛋奶酪饼,宛如一颗璀璨的明珠,散发着独特的魅力。 这款蛋奶酪饼,是传统工艺与现代口味的完美融合。而当你继续品尝,鸡蛋的鲜嫩和奶酪的浓郁醇厚便会在口中交融…...

常用的图像增强操作
我们将介绍如何用PIL库实现一些简单的图像增强方法。 [!NOTE] 初始化配置 import numpy as np from PIL import Image, ImageOps, ImageEnhance import warningswarnings.filterwarnings(ignore) IMAGE_SIZE 640[!important] 辅助函数 主要用于控制增强幅度 def int_param…...

探索TinyDB的轻量级魅力:Python中的微型数据库
文章目录 探索TinyDB的轻量级魅力:Python中的微型数据库背景:为何选择TinyDB?什么是TinyDB?如何安装TinyDB?5个简单的库函数使用方法3个场景下的应用实例常见问题与解决方案总结 探索TinyDB的轻量级魅力:Py…...

模型优化学习笔记—Adam算法
首先复习一下: 动量梯度下降: 1、算出dw、db 2、计算指数加权(移动)平均 vdw k *vdw (1-k)*dw vdb k *vdb (1-k)*db 3、梯度下降 w w - r*vdw b b - r*vdb RMSprop: 1、算出dw和db 2、算指数平均值&am…...

车辆出险报告(h5)-车辆出险记录接口-车辆相关接口
接口简介:通过vin及行驶证查询车辆出险、理赔、事故记录接口。查询成功率99%,返回URL地址的查询报告。 不能对返回的报告进行任何的修改,否则由用户自行承担相应的责任 报告结果只保留30天,如需永久保存,请您查询后自行保存 接口地…...

C基础项目(学生成绩管理系统)
目录 一、项目要求 二、完整代码实例 三、分文件编写代码实例 一、项目要求 1.系统运行,打开如下界面。列出系统帮助菜单(即命令菜单),提示输入命令 2.开始时还没有录入成绩,所以输入命令 L 也无法列出成绩。应提…...

C# 设计模式之原型模式
总目录 前言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在内存中…...

美林数据Tempo Talents | 两大资源中心,打造开放、成长型数智人才能力平台
在数字化时代的大潮中,高校作为知识与人才培养的重要阵地,独立分散的课程资源管理方式已无法满足现代教育的需求,而数据资源的分散和碎片化也阻碍了科研和教学工作的深入进行。那么,高校如何打造一个集中、高效的课程与数据资源中…...

IDC权威认可!工业领域最佳实践案例!
近日,IDC发布了《工业领域中数据管理分析服务最佳实践案例》报告,总结行业用户在应用过程中面临的主要挑战和实践路径,并评选最佳实践案例,为行业用户提供了相关的指导建议,供市场参考。星环科技中航电梯数据中台项目入…...

未授权访问漏洞系列详解①!
Redis未授权访问漏洞 Redis 默认情况下,会绑定在 0.0.0.0:6379 ,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,如果在没有设置密码认证(一般为空)的…...