IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 如何让C++字符串更快 in C++【C++学习笔记】 -> 正文阅读

[C++知识库]如何让C++字符串更快 in C++【C++学习笔记】

80.如何让C++字符串更快

字符串实际上是字符数组,所以对于string的主要问题,可能就是字符串格式化以及字符串的操作,这是因为它们都要分配内存

🍅概述问题

之前说过内存分配在堆和栈上的区别和建议:能分配在栈上就别分配到堆上,因为把内存分配到堆上会降低程序的速度。

然而,std::string和它的很多函数都喜欢分配在堆上,这实际上并不理想

#include <string>
#include <iostream>

void PrintName(const std::string& name) {
    std::cout << name << "\n";
}

int main() {
    std::string name = "Cherno";
    PrintName(name);
    return 0;
}

而就像上面的这么简单的程序,系统便为我们分配了八个字节的内存,堆分配了一次

而我们堆分配发生的地方,就是在创建字符串的地方std::string name = "CHerno";

而即使是最简单的

PrintName("Cherno");

在调用这个函数时,其构造函数依旧会分配其内存

然而这个例子还不够猛,还要再来点东西

#include <string>
#include <iostream>

void PrintName(const std::string& name) {
    std::cout << name << "\n";
}

int main() {
    std::string name = "Cherno";//1
    
    //加了俩substr切割字符串
    std::string firstName = name.substr(0, 3);//2
    std::string lastName = name.substr(3, 3);//3
    
    PrintName(name);
    return 0;
}

而在上面的例子中,程序分配了三次8字节的内存,每一次都分配到堆上

而做了这么点事情就有三次了,便可以想象这种事可能会在你的程序里经常发生了,相当损害速度

而如何解决呢?

🍅解决方案

在使用substr时,这个函数会自己处理完原字符串后创建出一个全新的字符串,它可以变换并有自己的内存

但是我们真正要想的是那个字符串的视图(意思是我只想看看原字符串剪完以后是什么样子的,不想再利用剪完后的全新的串

💡💡💡而这就是string_view发挥作用的地方了

std::string_view是C++17中的一个新类(但是还是可以用别的原始的方法去实现这个做法)

它的本质上,只是一个指向现有内存的指针,换句话说,就是一个const char指针,指向其他人拥有的现有字符串,再加上一个大小size

  • 我可以有一个指向第一个字符的指针,然后大小是3,而这就是我的子字符串。
  • 我可以有一个指针,指向那个字符串的开头加上四个字节,把我带到子字符串的开头

换句话说,我在创建一个窗口,一个进入现有内存的小视图,而不是分配一个新的字符串,不是用substr()创建一个新的字符串

  • 意思便是在观察一个已有的字符串

做这种事其实很简单,所以早在C++17之前,人们就在做这样的事情,这实际上是很常见的。观察已有字符串是没有内存分配的按值传递字符串视图是非常轻量级的

所以重写上面的程序

#include <string>
#include <iostream>

//在传递字符串的时候,不需要通过引用或类似的方式传递
//直接string_view
void PrintName(std::string_view name) {
    std::cout << name << "\n";
}

int main() {
    std::string name = "Cherno";
    
    /*
    std::string firstName = name.substr(0, 3);
    std::string lastName = name.substr(3, 3);
    */
    
    //这里可以用构造函数来指定子字符串,而这里也的确这样用了,通过name.c_str()
    //name.c_str(),意思是:属于字符串name的const char* 类型
    //作用就是得到了C语言风格的字符串,仅仅一个指针
    std::string_view firstName(name.c_str(), 0);
    std::string_view lastName(name.c_str() + 3, 3);	//可以不用从开头开始,可以直接从name.c_str()上加数字
    
    PrintName(name);
    return 0;
}

利用string_view去观察子字符串,去分配函数形参之后,测试出来的内存分配结果是:我们只是从这个原始字符串中得到仅仅一次堆上的分配

这很好了,但还可以更好,可以完全不需要分配内存!

做到这一点,则需要完全不使用std::string

#include <string>
#include <iostream>

void PrintName(std::string_view name) {
    std::cout << name << "\n";
}

int main() {
    //不用标准库里的std::string,而是用const char*
    const char* name = "Cherno";
    
    //这里就不需要专门针对std::string的c_str()了,就直接上数字便可
    //因为name这里代表的是指向字符串第一个字符的指针
    std::string_view firstName(name, 0);
    std::string_view lastName(name + 3, 3);	
    
    PrintName(name);
    return 0;
}

这般,完成在堆上完全0分配内存

💡💡💡这里的"Cherno"其实还是字符串,但是被分配到了栈上

亦可笼统称为字符串视图

所以如果不是有特殊的需求,尽量开始用string_view去替换掉这些字符串

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-10 11:40:56  更:2022-05-10 11:42:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 23:36:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码