当前位置: 首页 > news >正文

【C++】运算符重载案例 - 字符串类 ② ( 重载 等号 = 运算符 | 重载 数组下标 [] 操作符 | 完整代码示例 )

文章目录

  • 一、重载 等号 = 运算符
    • 1、等号 = 运算符 与 拷贝构造函数
    • 2、重载 等号 = 运算符 - 右操作数为 String 对象
    • 3、不同的右操作数对应的 重载运算符函数
  • 二、重载 下标 [] 运算符
  • 三、完整代码示例
    • 1、String.h 类头文件
    • 2、String.cpp 类实现
    • 3、Test.cpp 测试类
    • 4、执行结果





一、重载 等号 = 运算符




1、等号 = 运算符 与 拷贝构造函数


等号 = 操作符 的 作用是 使用一个现有对象 为 另外一个现有对象赋值 ;

  • 注意与 拷贝构造函数 区分 , 拷贝构造函数是 使用一个先有对象 为 一个新的对象进行初始化 ;
  • 下面的代码中 , 分别调用 等号操作符 和 拷贝构造函数 ;
String s1, s2;
s1 = s2;		// 这是使用 等号操作符 进行运算
String s3 = s2; // 这是使用 拷贝构造函数

2、重载 等号 = 运算符 - 右操作数为 String 对象


使用 成员函数 实现 重载 等号 = 运算符 :

  • 首先 , 写出函数名 , 函数名规则为 " operate " 后面跟上要重载的运算符 ,
    • 2 2 2 个对象 Student s1, s2 之间进行 等号运算 , 使用一个现有对象 为 另外一个现有对象赋值 ;
    • 使用时用法为 s1 = s2 ;
    • 函数名是 operator= ;
operator=
  • 然后 , 根据操作数 写出函数参数 , 参数一般都是 对象的引用 ;
    • 等号运算符 使用时用法为 s1 = s2 ;
    • 左操作数 : 其中 左操作数 是 s1 , 这里通过 this 指针调用 , 不需要声明在参数中 ;
    • 右操作数 - 情况 ① : 右操作数 也是 String 对象 ; 该操作数需要声明在参数中 , 注意 普通数据类型 直接声明 , 对象数据类型 需要声明 为 引用类型 ;
    • 上述两个是对象类型 , 对象一般传入 指针 或 引用 , 由于是基础数据类型 , 这里传入基础数据类型 ; 如果是 对象类型 , 则传入引用 ;
    • 右操作数 - 情况 ② : 还有一种情况是 s1 = "Tom" 的用法 , 这样 右操作数 是 char* 类型的字符串 ;
operator=(const String& s)	// 传入 String 对象 , 使用 const 修饰参数 , 防止传入的对象被修改
operator=(const char* p)	// 传入字符串值
  • 再后 , 根据业务完善返回值 , 返回值可以是 引用 / 指针 / 元素 ;
    • 此处返回值返回 String& 对象引用 , 可用于其它链式调用 ;
    • 如果返回 String 对象 , 则是一次性的匿名对象 ;
String& operator=(const String& s)	// 传入 String 对象 , 使用 const 修饰参数 , 防止传入的对象被修改
String& operator=(const char* p)	// 传入字符串值
  • 最后 , 实现函数体 , 编写具体的运算符操作业务逻辑 ;
    • 先把本对象已分配的内存释放掉 ;
    • 再进行赋值操作 ;

3、不同的右操作数对应的 重载运算符函数


不同的右操作数对应的 重载运算符函数 :

  • 右操作数是 String 对象的情况 :
// 重载等号 = 操作符 , 右操作数是 String 对象的情况
String& String::operator=(const String& s)
{// 先处理本对象已分配的内存if (this->m_p != NULL){// 之前使用 new 分配的内存// 释放内存就需要使用 delete // 使用 malloc 分配的内存需要使用 free 释放delete[] this->m_p;// 设置指针指为空 , 避免出现野指针this->m_p = NULL;// 设置字符串长度为 0this->m_len = 0;}// 拷贝字符串长度// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'this->m_len = s.m_len;// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocthis->m_p = new char[this->m_len + 1];// 拷贝字符串到 m_p 指向的内存中strcpy(this->m_p, s.m_p);cout << "调用重载等号 = 操作符函数 String& String::operator=(const String& s)" << endl;return *this;
}
  • 右操作数为 字符串指针 的情况 :
// 重载等号 = 操作符 , 右操作数是 字符串常量值 的情况
String& String::operator=(const char* p)
{// 先处理本对象已分配的内存if (this->m_p != NULL){// 之前使用 new 分配的内存// 释放内存就需要使用 delete // 使用 malloc 分配的内存需要使用 free 释放delete[] this->m_p;// 设置指针指为空 , 避免出现野指针this->m_p = NULL;// 设置字符串长度为 0this->m_len = 0;}// 拷贝字符串长度// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'this->m_len = strlen(p);// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocthis->m_p = new char[this->m_len + 1];// 拷贝字符串到 m_p 指向的内存中strcpy(this->m_p, p);cout << "调用重载等号 = 操作符函数 String& String::operator=(const char* p)" << endl;return *this;
}




二、重载 下标 [] 运算符



使用 成员函数 实现 重载 下标 [] 运算符 :

  • 首先 , 写出函数名 , 函数名规则为 " operate " 后面跟上要重载的运算符 ,
    • 下标 [] 运算符 , 使用时用法为 s[10] ;
    • 重载 下标 [] 运算符 函数名是 operator[] ;
operator[]
  • 然后 , 根据操作数 写出函数参数 , 参数一般都是 对象的引用 ;
    • 下标 运算符 使用时用法为 s[10] ;
    • 左操作数 : 其中 左操作数 是 s 对象 , 这里通过 this 指针调用 , 不需要声明在参数中 ;
    • 右操作数 : 右操作数 是 int 类型 索引值 ;
operator[](int i)
  • 再后 , 根据业务完善返回值 , 返回值可以是 引用 / 指针 / 元素 ;
    • 此处返回值 是 char 类型的 , 返回具体字符串指定索引的 char 类型字符 ;
    • char 字符是内存中的一个地址中的值 , 这里返回引用类型 ;
char& operator[](int i)
  • 最后 , 实现函数体 , 编写具体的运算符操作业务逻辑 ;
// 重载 数组下标 [] 操作符
char& String::operator[](int i)
{// 直接返回对应 i 索引字符return this->m_p[i];
}




三、完整代码示例




1、String.h 类头文件


#pragma once#include "iostream"
using namespace std;class String
{
public:// 默认的无参构造函数String();// 有参构造函数 , 接收一个 char* 类型字符串指针String(const char* p);// 拷贝构造函数 , 使用 String 对象初始化 对象值String(const String& s);// 析构函数~String();public:// 重载等号 = 操作符 , 右操作数是 String 对象的情况String& operator=(const String& s);// 重载等号 = 操作符 , 右操作数是 字符串常量值 的情况String& operator=(const char* p);// 重载 数组下标 [] 操作符char& operator[](int i);private:// 字符串长度 , 不包括 '\0'// 内存占用空间大小 = 字符串长度 + 1int m_len;// 字符串指针, 指向堆内存中的字符串char* m_p;
};

2、String.cpp 类实现


// 使用 strcpy 函数报错
// error C4996: 'strcpy': This function or variable may be unsafe. 
// Consider using strcpy_s instead. 
// To disable deprecation, use _CRT_SECURE_NO_WARNINGS. 
// See online help for details.
#define _CRT_SECURE_NO_WARNINGS#include "String.h"// 默认的无参构造函数
String::String()
{// 默认构造一个空字符串 , 字符串长度为 0 // 但是 , 字符串指针 指向的内存空间大小是 1 , 内容是 '\0'm_len = 0;// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocm_p = new char[m_len + 1];// 拷贝空字符串到 m_p 指向的内存中strcpy(m_p, "");cout << "调用无参构造函数" << endl;
}// 有参构造函数 , 接收一个 char* 类型字符串指针
String::String(const char* p)
{if (p == NULL){// 默认构造一个空字符串 , 字符串长度为 0 // 但是 , 字符串指针 指向的内存空间大小是 1 , 内容是 '\0'this->m_len = 0;// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocthis->m_p = new char[this->m_len + 1];// 拷贝空字符串到 m_p 指向的内存中strcpy(m_p, "");}else{// 获取传入字符串的长度// 但是 , 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'this->m_len = strlen(p);// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocthis->m_p = new char[this->m_len + 1];// 拷贝字符串到 m_p 指向的内存中strcpy(m_p, p);}cout << "调用有参构造函数" << endl;
};// 拷贝构造函数 , 使用 String 对象初始化 对象值
String::String(const String& s)
{// 拷贝字符串长度// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'this->m_len = s.m_len;// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocthis->m_p = new char[this->m_len + 1];// 拷贝字符串到 m_p 指向的内存中strcpy(this->m_p, s.m_p);cout << "调用拷贝构造函数" << endl;
}// 析构函数
String::~String()
{if (this->m_p != NULL){// 之前使用 new 分配的内存// 释放内存就需要使用 delete // 使用 malloc 分配的内存需要使用 free 释放delete[] this->m_p;// 设置指针指为空 , 避免出现野指针this->m_p = NULL;// 设置字符串长度为 0this->m_len = 0;}
}// 重载等号 = 操作符 , 右操作数是 String 对象的情况
String& String::operator=(const String& s)
{// 先处理本对象已分配的内存if (this->m_p != NULL){// 之前使用 new 分配的内存// 释放内存就需要使用 delete // 使用 malloc 分配的内存需要使用 free 释放delete[] this->m_p;// 设置指针指为空 , 避免出现野指针this->m_p = NULL;// 设置字符串长度为 0this->m_len = 0;}// 拷贝字符串长度// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'this->m_len = s.m_len;// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocthis->m_p = new char[this->m_len + 1];// 拷贝字符串到 m_p 指向的内存中strcpy(this->m_p, s.m_p);cout << "调用重载 等号 = 操作符函数 String& String::operator=(const String& s)" << endl;return *this;
}// 重载等号 = 操作符 , 右操作数是 字符串常量值 的情况
String& String::operator=(const char* p)
{// 先处理本对象已分配的内存if (this->m_p != NULL){// 之前使用 new 分配的内存// 释放内存就需要使用 delete // 使用 malloc 分配的内存需要使用 free 释放delete[] this->m_p;// 设置指针指为空 , 避免出现野指针this->m_p = NULL;// 设置字符串长度为 0this->m_len = 0;}// 拷贝字符串长度// 注意 : 字符串指针 指向的内存空间大小需要 +1 , 内容是 '\0'this->m_len = strlen(p);// 使用 new 关键字为 char* m_p; 指针分配内存// 对于基础数据类型 new 等同于 mallocthis->m_p = new char[this->m_len + 1];// 拷贝字符串到 m_p 指向的内存中strcpy(this->m_p, p);cout << "调用重载 等号 = 操作符函数 String& String::operator=(const char* p)" << endl;return *this;
}// 重载 数组下标 [] 操作符
char& String::operator[](int i)
{cout << "调用重载 下标 [] 操作符函数 char& String::operator[](int i)" << endl;// 直接返回对应 i 索引字符return this->m_p[i];
}

3、Test.cpp 测试类


#include "iostream"
using namespace std;// 导入自定义的 String 类
#include "String.h"int main() {// 调用无参构造函数String s1;// 调用有参构造函数String s2("Tom");// 调用拷贝构造函数String s3 = s2;// 调用重载的等号运算符函数, 右操作数是 String 对象s1 = s2;// 调用重载的等号运算符函数, 右操作数是 字符串常量值 , char* 指针类型s3 = "Jerry";// 调用重载的下标运算符函数char c = s3[3];// 控制台暂停 , 按任意键继续向后执行system("pause");return 0;
}

4、执行结果


执行结果 :

调用无参构造函数
调用有参构造函数
调用拷贝构造函数
调用重载 等号 = 操作符函数 String& String::operator=(const String& s)
调用重载 等号 = 操作符函数 String& String::operator=(const char* p)
调用重载 下标 [] 操作符函数 char& String::operator[](int i)

在这里插入图片描述

相关文章:

【C++】运算符重载案例 - 字符串类 ② ( 重载 等号 = 运算符 | 重载 数组下标 [] 操作符 | 完整代码示例 )

文章目录 一、重载 等号 运算符1、等号 运算符 与 拷贝构造函数2、重载 等号 运算符 - 右操作数为 String 对象3、不同的右操作数对应的 重载运算符函数 二、重载 下标 [] 运算符三、完整代码示例1、String.h 类头文件2、String.cpp 类实现3、Test.cpp 测试类4、执行结果 一…...

Vue脚手架开发流程

一、项目运行时会先执行 public / index.html 文件 <!DOCTYPE html> <html lang""><head><meta charset"utf-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport&quo…...

从零开始学习线性回归:理论、实践与PyTorch实现

文章目录 &#x1f966;介绍&#x1f966;基本知识&#x1f966;代码实现&#x1f966;完整代码&#x1f966;总结 &#x1f966;介绍 线性回归是统计学和机器学习中最简单而强大的算法之一&#xff0c;用于建模和预测连续性数值输出与输入特征之间的关系。本博客将深入探讨线性…...

[LeetCode]链式二叉树相关题目(c语言实现)

文章目录 LeetCode965. 单值二叉树LeetCode100. 相同的树LeetCode101. 对称二叉树LeetCode144. 二叉树的前序遍历LeetCode94. 二叉树的中序遍历LeetCode145. 二叉树的后序遍历LeetCode572. 另一棵树的子树 LeetCode965. 单值二叉树 题目 Oj链接 思路 一棵树的所有值都是一个…...

集成学习

集成学习&#xff08;Ensemble Learning) - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/27689464集成学习就是组合这里的多个弱监督模型以期得到一个更好更全面的强监督模型&#xff0c;集成学习潜在的思想是即便某一个弱分类器得到了错误的预测&#xff0c;其他的弱分类器…...

算法练习11——买卖股票的最佳时机 II

LeetCode 122 买卖股票的最佳时机 II 给你一个整数数组 prices &#xff0c;其中 prices[i] 表示某支股票第 i 天的价格。 在每一天&#xff0c;你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买&#xff0c;然后在 同一天 出售。 返回…...

linux——多线程,线程控制

目录 一.POSIX线程库 二.线程创建 1.创建线程接口 2.查看线程 3.多线程的健壮性问题 4.线程函数参数传递 5.线程id和地址空间 三.线程终止 1.pthread_exit 2.pthread_cancel 四.线程等待 五.线程分离 一.POSIX线程库 站在内核的角度&#xff0c;OS只有轻量级进程…...

Oracle 简介与 Docker Compose部署

最近&#xff0c;我翻阅了在之前公司工作时的笔记&#xff0c;偶然发现了一些有关数据库的记录。当初&#xff0c;我们的项目一开始采用的是 Oracle 数据库&#xff0c;但随着项目需求的变化&#xff0c;我们不得不转向使用 SQL Server。值得一提的是&#xff0c;公司之前采用的…...

mp4音视频分离技术

文章目录 问题描述一、分离MP3二、分离无声音的MP4三、结果 问题描述 MP4视频想拆分成一个MP3音频和一个无声音的MP4文件 一、分离MP3 ffmpeg -i C:\Users\Administrator\Desktop\一个文件夹\我在财神殿里长跪不起_完整版MV.mp4 -vn C:\Users\Administrator\Desktop\一个文件…...

JVM 参数

JVM 参数类型大致分为以下几类&#xff1a; 标准参数&#xff08;-&#xff09;&#xff1a;保证在所有的 JVM 实现都支持的参数非标准参数&#xff08;-X&#xff09;&#xff1a;通用的&#xff0c;特定于 HotSpot 虚拟机的参数&#xff0c;这些参数不保证在所有 JVM 实现中…...

黑马点评-07缓存击穿问题(热点key失效)及解决方案,互斥锁和设置逻辑过期时间

缓存击穿问题(热点key失效) 缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且重建缓存业务较复杂的key突然失效了,此时无数的请求访问会在瞬间打到数据库,带来巨大的冲击 一件秒杀中的商品的key突然失效了&#xff0c;由于大家都在疯狂抢购那么这个瞬间就会有无数的请求…...

信息系统项目管理师第四版学习笔记——项目进度管理

项目进度管理过程 项目进度管理过程包括&#xff1a;规划进度管理、定义活动、排列活动顺序、估算活动持续时间、制订进度计划、控制进度。 规划进度管理 规划进度管理是为规划、编制、管理、执行和控制项目进度而制定政策、程序和文档的过程。本过程的主要作用是为如何在…...

指挥棒:C++ 与运算符

文章目录 参考描述算术运算符除法运算取模运算复合赋值运算符自增运算符自减运算符 比较运算符逻辑运算符概念短路为什么需要短路机制&#xff1f; 参考 项目描述微软C 语言文档搜索引擎Bing、GoogleAI 大模型文心一言、通义千问、讯飞星火认知大模型、ChatGPTC Primer Plus &…...

HTTPS建立连接的过程

HTTPS 协议是基于 TCP 协议的&#xff0c;因而要先建立 TCP 的连接。在这个例子中&#xff0c;TCP 的连接是在手机上的 App 和负载均衡器 SLB 之间的。 尽管中间要经过很多的路由器和交换机&#xff0c;但是 TCP 的连接是端到端的。TCP 这一层和更上层的 HTTPS 无法看到中间的包…...

Python接口自动化搭建过程,含request请求封装!

开篇碎碎念 接口测试自动化好处 显而易见的好处就是解放双手&#x1f600;。 可以在短时间内自动执行大量的测试用例通过参数化和数据驱动的方式进行测试数据的变化&#xff0c;提高测试覆盖范围快速反馈测试执行结果和报告支持持续集成和持续交付的流程 使用Requestspytes…...

Vue3 编译原理

文章目录 一、编译流程1. 解读入口文件 packgages/vue/index.ts2. compile函数的运行流程 二、AST 解析器1. ast 的生成2. 创建ast的根节点3. 解析子节点 parseChildren&#xff08;关键&#xff09;4. 解析模版元素 Element模版元素解析-举例分析 一、编译流程 1. 解读入口文…...

spring boot整合Minio

MinIO 安装MinIo # 先创建minio 文件存放的位置 mkdir -p /opt/docker/minio/data# 启动并指定端口 docker run \-p 9000:9000 \-p 5001:5001 \--name minio \-v /opt/docker/minio/data:/data \-e "MINIO_ROOT_USERminioadmin" \-e "MINIO_ROOT_PASSWORDmini…...

Hadoop----Azkaban的使用与一些报错问题的解决

1.因为官方只放出源码&#xff0c;并没有放出其tar包&#xff0c;所以需要我们自己编译&#xff0c;通过查阅资料我们可以使用gradlew对其进行编译&#xff0c;还是比较简单&#xff0c;然后将里面需要用到的服务文件夹进行拷贝&#xff0c;完善其文件夹结构&#xff0c;通常会…...

「新房家装经验」客厅电视高度标准尺寸及客厅电视机买多大尺寸合适?

客厅电视悬挂高度标准尺寸是多少&#xff1f; 客厅电视悬挂高度通常在90~120厘米之间&#xff0c;电视挂墙高度也可以根据个人的喜好和实际情况来调整&#xff0c;但通常不宜过高&#xff0c;以坐在沙发上观看时眼睛能够平视到电视中心点或者中心稍微往下一点的位置为适宜。 客…...

ArduPilot开源飞控之AP_Baro_DroneCAN

ArduPilot开源飞控之AP_Baro_DroneCAN 1. 源由2. back-end抽象类3. 方法实现3.1 probe3.2 update3.3 subscribe_msgs3.4 handle_pressure/handle_temperature3.5 CAN port 4. 参考资料 1. 源由 鉴于ArduPilot开源飞控之AP_Baro中涉及Sensor Driver有以下总线类型&#xff1a; …...

把旧路由器改造成远程ADB调试服务器:OpenWrt安装adb与公网访问指南

旧路由器变身远程ADB调试服务器&#xff1a;OpenWrt实战指南 在移动应用开发过程中&#xff0c;频繁连接USB数据线进行调试不仅效率低下&#xff0c;更限制了开发者的工作灵活性。想象一下&#xff0c;当你需要同时调试多台设备&#xff0c;或者在不同网络环境下快速切换测试场…...

蓝牙学习1(基础知识)(TODO)

https://mp.weixin.qq.com/s/qjKsxuF4TRrH5CWh8TOvzw 蓝牙点灯 1 蓝牙 蓝牙&#xff08;Bluetooth&#xff09;是一种短距离无线通信技术&#xff0c;用于在电子设备之间传输数据或建立语音连接。它采用2.4GHz ISM频段&#xff08;2.402GHz–2.480GHz&#xff09;&#xff0c…...

Ryujinx模拟器三部曲:从新手到专家的Switch游戏PC体验进阶指南

Ryujinx模拟器三部曲&#xff1a;从新手到专家的Switch游戏PC体验进阶指南 【免费下载链接】Ryujinx 用 C# 编写的实验性 Nintendo Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/ry/Ryujinx 你是否曾梦想在电脑上畅玩《塞尔达传说&#xff1a;旷野之息…...

NoFences:5分钟彻底告别Windows桌面混乱的开源分区神器

NoFences&#xff1a;5分钟彻底告别Windows桌面混乱的开源分区神器 【免费下载链接】NoFences &#x1f6a7; Open Source Stardock Fences alternative 项目地址: https://gitcode.com/gh_mirrors/no/NoFences 你是否每天面对杂乱的Windows桌面感到无从下手&#xff1f…...

autoloom:自动化工作流编排框架的设计原理与实践指南

1. 项目概述与核心价值最近在GitHub上看到一个挺有意思的项目&#xff0c;叫autoloom&#xff0c;作者是thresher-sh。光看名字&#xff0c;可能有点摸不着头脑&#xff0c;但如果你正在处理一些需要“编织”或“缝合”多个独立数据源、API接口、微服务或者自动化流程的任务&am…...

EFM8 I2C Slave外设深度解析:从SMBus思维转换到实战应用

1. 项目概述&#xff1a;从SMBus到I2C Slave的思维转换如果你之前主要接触的是SMBus&#xff08;系统管理总线&#xff09;设备&#xff0c;现在要上手Silicon Labs的EFM8LB1或EFM8BB3这类8位MCU的I2C Slave&#xff08;从机&#xff09;功能&#xff0c;可能会觉得有点“水土不…...

用Monster M4SK打造可穿戴互动眼睛:从硬件拆解到凯皮帽子制作

1. 项目概述&#xff1a;当马里奥的帽子“活”了过来如果你和我一样&#xff0c;既是任天堂游戏的粉丝&#xff0c;又对嵌入式硬件和可穿戴设备着迷&#xff0c;那么把游戏里的角色带到现实中来&#xff0c;绝对是一件充满乐趣的事。这次我们要“复活”的&#xff0c;是《超级马…...

拆解MC1496乘法器:如何在没有现成库的Multisim里,手动封装一个调幅核心模块

从零构建MC1496乘法器&#xff1a;Multisim高阶封装与调幅电路实战指南 在电子设计领域&#xff0c;仿真软件自带的元件库往往无法满足所有需求。当我们需要使用MC1496这类经典模拟乘法器时&#xff0c;Multisim的默认库可能让人束手无策。本文将带您深入芯片内部结构&#xff…...

ARM PMU中断控制寄存器PMINTENCLR/PMINTENSET详解

1. ARM性能监控单元(PMU)架构概述 在现代处理器设计中&#xff0c;性能监控单元(Performance Monitoring Unit, PMU)是实现系统级性能分析和优化的关键组件。ARM架构从v7开始引入标准化的PMU设计&#xff0c;并在v8/v9架构中持续演进。PMU的核心功能是通过一组可编程事件计数器…...

从压测到瓶颈定位:一次完整的性能分析思路

很多人刚接触压测时&#xff0c;会产生一种错觉&#xff1a;“压测不就是看 QPS 吗&#xff1f;”但压测的本质&#xff0c;从来不是“跑数字”&#xff0c;而是&#xff1a;找到系统的性能极限&#xff0c;以及限制系统性能的真正瓶颈。 本文会围绕下面几个核心问题&#xff0…...