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定义 首…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...
【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道
文/法律实务观察组 在债务重组领域,专业机构的核心价值不仅在于减轻债务数字,更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明,合法债务优化需同步实现三重平衡: 法律刚性(债…...
人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型
在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重,适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解,并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...
aardio 自动识别验证码输入
技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”,于是尝试整合图像识别与网页自动化技术,完成了这套模拟登录流程。核心思路是:截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章 摘要: 操作系统内核的安全性、稳定性至关重要。传统 Linux 内核模块开发长期依赖于 C 语言,受限于 C 语言本身的内存安全和并发安全问题,开发复杂模块极易引入难以…...
ZYNQ学习记录FPGA(二)Verilog语言
一、Verilog简介 1.1 HDL(Hardware Description language) 在解释HDL之前,先来了解一下数字系统设计的流程:逻辑设计 -> 电路实现 -> 系统验证。 逻辑设计又称前端,在这个过程中就需要用到HDL,正文…...
