string模拟优化和vector使用
1.简单介绍编码
utf_8变长编码,常用英文字母使用1个字节,对于其它语言可能2到14,大部分编码是utf_8,char_16是编码为utf_16, char_32是编码为utf_32, wchar_t是宽字符的,
utf_16是大小为俩个字节,所以牛马还有一个'\0'一个是3*2六个字节
utf_32是大小为四个字节所以大小就是3*4十二个字节
wchar_t 在window上通常为2字节,其它环境有不同大小。
char16_t str16[] = u"牛马";char32_t str32[] = U"牛马";wchar_t wstr[] = L"牛马";cout << sizeof(str) << endl;cout << sizeof(str16) << endl;cout << sizeof(str32) << endl;cout << sizeof(wstr) << endl;*/
2.对于拷贝优化
省略的部分是可以用上面的代替,先构造一个tmp出来,然后把s1复制到tmp上,再去交换s2和tmp,这里是浅拷贝了指针,如果不用交换而是直接把指针值复制过去会有野指针的问题,因为另一个被复制的变量如果被销毁了,那么它指向的空间也会被收回,浅拷贝是一个一个字节复制的,所以此时还剩一个变量指向被释放的空间就会有问题,而swap可以很好的解决,交换完后tmp销毁了,但是销毁的是s1的空间。
void test_string6(){string s1("hello world");string s2 = s1;cout << s1 << endl;cout << s2 << endl;string s3("xxxxxxxxxxxxxx");s1 = s3;cout << s1 << endl;cout << s3 << endl;}
string(const char* str = ""){_size = strlen(str);// _capacity不包含\0_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}string(const string& s){string tmp(s._str);swap(tmp);}// 深拷贝问题// s2(s1)/*string(const string& s){_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}*/void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}
3.赋值运算符重载
先判断是否相等,是则直接结束,不一样就构造tmp并拷贝,然后交换,这里的if除了判断是否一样还有其它作用,{}符号表明了一个局部作用域,所以局部变量在出了这个{}会被销毁,tmp就会被销毁,一举两得。
//s1 = s3;string& operator=(const string& s){if (this != &s){//string tmp(s._str);string tmp(s);swap(tmp);}return *this;}
下面是进一步优化
在形参数部分变为string tmp,这样s3作为参数时,先构造tmp然后指向拷贝构造,这里swap只写tmp是因为还有一个隐式参数*this,所以交换,除了{}tmp销毁,代码简洁性高。
// s1 = s3;string& operator=(string tmp){swap(tmp);return *this;}
4.swap
可以看到模板的swap是先拷贝c,然后在赋值运算符重载俩次,注意如果a和b都有指向资源,那么就要用深拷贝,那么一次swap就三次深拷贝,是非常占资源的,所以用上面的就相对效率高,如果字节的类里面有,这里的std::swap调用的却是全局的swap,全局的swap效率高于模板swap(std::swap),而且有实例化的swap也不会去模板生成swap。是因为编译器会去找最适配的swap,就像你像吃辣条,你的妈妈却还是给你买健康的食品。
5.简单介绍引用计数和写时拷贝
引用计数:在加一个变量来记录有多少个指针指向这个空间,这样就有判断的标准,如果大于1就是有多个指向这块空间,等于一就说明只有一个指针指向这里,可以自由修改,也不会有多次析构。
写时拷贝:
写时拷贝是一种优化技术,通常用于减少内存使用和提高性能。它允许多个对象共享同一份数据,直到有一个对象需要修改这份数据为止。只有在需要修改时,才会进行数据的实际拷贝,从而避免不必要的内存分配和复制操作
6.vector简单使用
1.创建vector
创建俩个vector变量,vector是stl的模板要显式实例化,可以看到不写参数是走缺省参数的,而10,1就是10个int的元素,值为1。
用reserve(域string的作用一样,提前开空间),可以看到比原来大会改变,再改小则不会变化。
vector<int> v2(10, 1);v2.reserve(15);cout << v2.size() << endl;cout << v2.capacity() << endl;v2.reserve(25);cout << v2.size() << endl;cout << v2.capacity() << endl;v2.reserve(5);cout << v2.size() << endl;cout << v2.capacity() << endl;
2.使用resize
resize函数会改变vector实例对象的大小,当为5时就只有五个在vector里面,
这里是如果扩大则会填充第二个参数,一开始是10个1,后面变成15,则再填5个2,25就再填10个3.
void test_vector3()
{//TestVectorExpand();vector<int> v(10, 1);v.reserve(20);cout << v.size() << endl;cout << v.capacity() << endl;v.resize(15, 2);cout << v.size() << endl;cout << v.capacity() << endl;v.resize(25, 3);cout << v.size() << endl;cout << v.capacity() << endl;v.resize(5);cout << v.size() << endl;cout << v.capacity() << endl;
}
3.二维的vector
先初始化一个一维的v,然后以v为参数构造二维的vv,
vector<int> v(10, 1);vector<vector<int>> vv(5,v);
4.迭代器和范围for遍历vector
这里前置++和前置--则最后只有八位打印出来,因为是从begin后一位和end前一位,循环和范围for也可以逐个打印,像之前的数组一样。
void test_vector1()
{vector<int> v1;vector<int> v2(10, 1);vector<int> v3(++v2.begin(), --v2.end());for (size_t i = 0; i < v3.size(); i++){cout << v3[i] << " ";}cout << endl;vector<int>::iterator it = v3.begin();while (it != v3.end()){cout << *it << " ";++it;}cout << endl;for (auto e : v3){cout << e << " ";}cout << endl;
}
5.vector的操作
insert是在vector中插入数据,前一个是位置,后一个是插入什么元素,后面用for来cin初始化vector。
vector<int> v(10, 1);v.push_back(2);v.insert(v.begin(), 0);for (auto e : v){cout << e << " ";}cout << endl;v.insert(v.begin() + 3, 10);for (auto e : v){cout << e << " ";}cout << endl;vector<int> v1(5, 0);for (size_t i = 0; i < 5; i++){cin >> v1[i];}for (auto e : v1){cout << e << ",";}cout << endl;
前面知识补充:
在 C++ 中,可以使用强制转换将指针类型转换为 void*,这是合法的,且在某些情况下非常有用。下面,我将详细解释如何在 C++ 中使用 void*,以及在与 std::cout 结合使用时的注意事项。
1. 强制转换为 void*
在 C++ 中,任何指针类型都可以被隐式或显式转换为 void*。void* 是一种通用指针类型,能够指向任何类型的数据。通过这种转换,你可以在不知道指针具体类型的情况下处理内存地址。这在处理底层内存操作或需要泛型编程的情况下特别有用。
2. 与 std::cout 的结合使用
如你所述,std::cout 对 const char* 类型进行了特别的处理,重载了 << 运算符以打印字符串的内容。如果你需要打印 const char* 的地址,可以使用 (void*) 来强制转换:
std::cout << (void*)cStr;这将输出指针的内存地址,而不是它指向的字符串内容。
3. 示例代码
以下是一个完整的示例代码,演示了如何使用 void* 强制转换以及打印字符串内容和指针地址的区别:
#include <iostream>
#include <string>int main() {
std::string str = "Hello, World!";
const char* cStr = str.c_str();// 输出字符串内容
std::cout << "内容: " << cStr << std::endl; // 输出: Hello, World!// 输出指针的地址
std::cout << "指针地址: " << (void*)cStr << std::endl; // 输出: 指针的内存地址return 0;
}4. 输出结果
运行上述代码时,输出将类似于:
内容: Hello, World!
指针地址: 0x7ffee6b7c3d0 // 这个值会因每次运行而不同5. 关键点总结
1.重载运算符:std::cout 对 const char* 类型的重载实现允许直接输出字符串内容。
2.地址输出:如果你想输出指针的地址,必须使用 (void*) 来进行强制转换。
3.合法性:使用强制转换 void* 是合法的,可以用于指针类型与通用指针之间的转换。6. 注意事项
虽然强制转换为 void* 是合法的,但在某些情况下需要谨慎使用:4.类型安全:使用 void* 可能会导致类型安全问题,尤其是在进行指针运算时。
5.需要显式转换回原始类型:在使用 void* 时,如果需要再次使用原始类型的指针,你必须显式地将其转换回来,这可能会引入错误。总的来说,使用 void* 是 C++ 中一种灵活的指针处理方式,但要注意相应的安全性和可读性问题。
在 C++ 中,std::string 类提供了 replace 函数,用于替换字符串中的部分内容。这个函数可以使用不同的参数形式,允许你根据需求替换子字符串或单个字符。
std::string::replace 函数的基本用法
1. 替换子字符串
使用 std::string::replace 来替换指定范围内的字符,可以按以下方式调用:
std::string& replace(size_t pos, size_t len, const std::string& str);
1.pos:要替换的起始位置。
2.len:要替换的字符数。
3.str:用于替换的字符串。示例代码:
#include <iostream>
#include <string>int main() {
std::string str = "Hello, world!";// 从位置 7 开始替换 5 个字符
str.replace(7, 5, "C++");std::cout << str << std::endl; // 输出: Hello, C++!
return 0;
}2. 替换单个字符
std::string::replace 也可以用来替换单个字符,示例如下:
std::string& replace(size_t pos, size_t len, size_t n, char c);
4.n:替换字符的数量。
5.c:要替换成的字符。示例代码:
#include <iostream>
#include <string>int main() {
std::string str = "Hello, world!";// 从位置 7 开始替换 5 个字符为字符 '*'
str.replace(7, 5, 3, '*');std::cout << str << std::endl; // 输出: Hello, ***d!
return 0;
}3. 替换另一个字符串
你还可以用另一个字符串的子串来替换当前字符串中的部分内容:
std::string& replace(size_t pos, size_t len, const char* s);示例代码:
#include <iostream>
#include <string>int main() {
std::string str = "Hello, world!";// 从位置 7 开始替换 5 个字符为 C 风格字符串 "C++"
str.replace(7, 5, "C++");std::cout << str << std::endl; // 输出: Hello, C++!
return 0;
}4. 替换多个字符
如果需要替换多个字符,可以使用 std::string::replace 结合字符串的长度来实现:
#include <iostream>
#include <string>int main() {
std::string str = "Hello, world! Hello, world!";// 替换所有 "world" 为 "C++"
size_t pos = 0;
std::string to_replace = "world";
std::string replace_with = "C++";while ((pos = str.find(to_replace, pos)) != std::string::npos) {
str.replace(pos, to_replace.length(), replace_with);
pos += replace_with.length(); // Move past the replaced part
}std::cout << str << std::endl; // 输出: Hello, C++! Hello, C++!
return 0;
}总结
std::string::replace 是一个强大的工具,可以灵活地对字符串中的部分内容进行替换。根据需要,可以选择替换字符、字符串或使用 C 风格字符串。通过适当的循环和查找,可以实现更复杂的替换操作。
相关文章:

string模拟优化和vector使用
1.简单介绍编码 utf_8变长编码,常用英文字母使用1个字节,对于其它语言可能2到14,大部分编码是utf_8,char_16是编码为utf_16, char_32是编码为utf_32, wchar_t是宽字符的, utf_16是大小为俩个字节&a…...
Go-知识依赖GOPATH
Go-知识依赖GOPATH 1. 介绍2. GOROOT 是什么3. GOPATH 是什么4. 依赖查找5. GOPATH 的缺点1. 介绍 早期Go语言单纯地使用GOPATH管理依赖,但是GOPATH不方便管理依赖的多个版本,后来增加了vendor,允许把项目依赖 连同项目源码一同管理。Go 1.11 引入了全新的依赖管理工具 Go …...
PyTorch 中 reshape 函数用法示例
PyTorch 中 reshape 函数用法示例 在 PyTorch 中,reshape 函数用于改变张量的形状,而不改变其中的数据。下面是一些关于 reshape 函数的常见用法示例。 基本语法 torch.reshape(input, shape) # input: 要重塑的张量。 # shape: 目标形状࿰…...
安全光幕的工作原理及应用场景
安全光幕是一种利用光电传感技术来检测和响应危险情况的先进设备。其工作原理基于红外线传感器,通过发射红外光束并接收反射或透射光束来形成一道无形的屏障。以下是对安全光幕工作原理和应用场景的介绍: 工作原理 发射器与接收器:安全光幕通…...

《深度学习》OpenCV LBPH算法人脸识别 原理及案例解析
目录 一、LBPH算法 1、概念 2、实现步骤 3、方法 1)步骤1 • 缩放 • 旋转和平移 2)步骤2 二、案例实现 1、完整代码 1)图像内容: 2)运行结果: 一、LBPH算法 1、概念 在OpenCV中,L…...

数据结构之顺序表——动态顺序表(C语言版)
静态顺序表我们已经实现完毕了,下来我们实现一下动态顺序表 静态链接:数据结构之顺序表——动态顺序表(C语言版) 首先来了解一下两个顺序表的差别 一、内存管理的灵活性 动态分配与释放:动态顺序表能够在运行时根据需要动态地分配和释放内存…...
Python 网络爬虫入门与实战
目录 1 引言 2 网络爬虫基础知识 2.1 什么是网络爬虫 2.2 爬虫的工作原理 2.3 爬虫的应用场景 3 Python 爬虫环境搭建 3.1 安装 Python 3.2 安装必要的库 4 使用 Requests 库进行基本爬虫 4.1 发送 GET 请求 4.2 发送 POST 请求 4.3 处理响应 5 使用 BeautifulSoup…...

成都睿明智科技有限公司电商服务可靠不?
在这个短视频风起云涌的时代,抖音不仅成为了人们娱乐消遣的首选平台,更是众多商家竞相追逐的电商新蓝海。成都睿明智科技有限公司,作为抖音电商服务领域的佼佼者,正以其独到的洞察力和专业的服务,助力无数品牌在这片沃…...

fmql之Linux Uart
正点原子第48章。 串口收发测试 正点原子教程 RS232和RS485的串口收发测试是一样的。 // 设置串口波特率为115200 stty -F /dev/ttyPS1 ispeed 115200 ospeed 115200 cs8// 发送字符串 echo "www.openedv.com" >/dev/ttyPS1// 接收数据 cat /dev/ttyPS1 fmql测…...

【火山引擎】调用火山大模型的方法 | SDK安装 | 配置 | 客户端初始化 | 设置
豆包 (Doubao) 是字节跳动研发的大规模预训练语言模型。 目录 1 安装 2 配置访问凭证 3 客户端初始化 4 设置地域和访问域名 5 设置超时/重试次数 1 安装 通过pip安装PYTHON SDK。 pip install volcengine-python-sdk[ark] 2 配置访问凭证 获取 API Key 访问凭证具体步…...

前端实现下载功能汇总(下载二进制流文件、数组下载成csv、将十六进制下载成pcap、将文件下载成zip)
前言:汇总一下做过的下载功能,持续补充中 一、将后端传过来的二进制流文件下载(需要提取headers里面的文件名) const { herders,data }res; // 创建下载链接元素 const link document.createElement("a");// 创建 Bl…...

iLogtail 开源两周年:UC 工程师分享日志查询服务建设实践案例
作者:UC 浏览器后端工程师,梁若羽 传统 ELK 方案 众所周知,ELK 中的 E 指的是 ElasticSearch,L 指的是 Logstash,K 指的是 Kibana。Logstash 是功能强大的数据处理管道,提供了复杂的数据转换、过滤和丰富…...
【MySQL】入门篇—基本数据类型:NULL值的概念
在关系数据库中,NULL值是一个特殊的标记,表示缺失或未知的值。 NULL并不等同于零(0)或空字符串(),它表示一个字段没有任何值。 这一概念在数据库设计和数据管理中至关重要,因为它影…...
Java设计模式10 - 观察者模式
观察者模式 观察者模式也叫作发布-订阅模式,也就是事件监听机制。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自…...

LabVIEW示波器通信及应用
基于LabVIEW平台开发的罗德与施瓦茨示波器通信与应用系统实现了示波器的远程控制及波形数据的实时分析,通过TCP/IP或USB接口与计算机通信,利用VISA技术进行指令传输,从而实现高效的数据采集与处理功能。 项目背景 随着现代电子测试需求的日益…...

西门子PLC中Modbus通讯DATA_ADDR通讯起始地址设置以及RTU轮询程序设计。
1 DATA_ADDR通讯起始地址设置 因为西门子PLC保持型寄存器的是40001~49999和400001~465536, 那么什么时候用40001什么时候用400001呢? 当需要的地址超过49999的话就用400001。 比如从站的某个地址是#16 48D518645 4000118645超过了49999 这边因为前…...

趋势(一)利用python绘制折线图
趋势(一)利用python绘制折线图 折线图( Line Chart)简介 折线图用于在连续间隔或时间跨度上显示定量数值,最常用来显示趋势和关系(与其他折线组合起来)。折线图既能直观地显示数量随时间的变化…...

【含文档】基于Springboot+Vue的采购管理系统(含源码+数据库+lw)
1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…...

【C++11入门基础】
我没有那么想你,那只是偶尔醉意会催人提起.......................................................................... 目录 前言 一、【C11的介绍】 二、【C11引入的一些实用语法】 2.1、【统一的列表初始化({ }的初始化)】 2.2、【initi…...

Pytest中fixture的scope详解
pytest作为Python技术栈下最主流的测试框架,功能极为强大和灵活。其中Fixture夹具是它的核心。而且pytest中对Fixture的作用范围也做了不同区分,能为我们利用fixture带来很好地灵活性。 下面我们就来了解下这里不同scope的作用 fixture的scope定义 首…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...

mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...