栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

如何让C++字符串更快 in C++【C++学习笔记】

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何让C++字符串更快 in C++【C++学习笔记】

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

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

概述问题

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

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

#include 
#include 

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 
#include 

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 
#include 

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

int main() {
    std::string name = "Cherno";
    
    
    
    //这里可以用构造函数来指定子字符串,而这里也的确这样用了,通过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 
#include 

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去替换掉这些字符串

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/869398.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号