C++标准库提供了一个非常优秀的字符串处理类std::string,我们可以通过该类完成各种字符串操作。但是std::string有一个缺点,它的很多操作都是针对字符串实体,存在不必要的内存拷贝的代码,导致字符串的处理性能不尽如人意。

针对这种情况C++17标准引入了std::string_view这个类,该类不会直接作用在字符串实体上,而是记录字符串处理的位置,这样就可以保证用最小的代价对字符串进行处理。

在几个月前写过 std::string_view 的一些简洁介绍,在其中有提及:Here

做函数形参的时候,使用std::string_view基本一定优于老式的const std::string&这种写法。

为了验证这个结论,下面的代码实现了一个断词器,然后针对 \(64MB\) 的数据做断词处理并且分别记录使用std::stringstd::string_view作为基础类型时断词器运行的时间:

#include <iostream>
#include <chrono>
#include <string_view> template<class T>
struct tokenizer {
using string_type = T;
using value_type = typename T::value_type; tokenizer(const string_type & str,
std::enable_if_t<std::disjunction_v<
std::is_same<string_type, std::basic_string<value_type>>,
std::is_same<string_type, std::basic_string_view<value_type>>>> * = nullptr)
: data_(str), begin_(0), end_(0) {} string_type operator()(const value_type sep) {
for ( ; end_ < data_.size(); ++end_ )
{
if (data_[end_] == sep)
{
auto res = data_.substr(begin_, end_ - begin_);
begin_ = ++end_;
return res;
}
}
if (end_ <= data_.size())
{
return data_.substr(begin_, end_);
} return "";
} bool more() const { return end_ < data_.size(); } private:
const string_type data_;
size_t begin_, end_;
}; auto make_string_data(size_t count, char sep) {
std::string data;
for ( size_t i = 0; i < count; ++i )
{
data.push_back('a' + i % 26);
if (i + 1 != count)
data.push_back(sep);
}
return data;
} int main() {
auto data = make_string_data(1024 * 1024 * 32, ' '); {
tokenizer<std::string> tk(data);
auto start = std::chrono::high_resolution_clock::now();
while ( tk.more())
{
tk(' ');
}
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = end - start;
std::cout << "elapsed time = " << diff.count() << std::endl;
} {
tokenizer<std::string_view> tk(data);
auto start = std::chrono::high_resolution_clock::now();
while ( tk.more())
{
tk(' ');
}
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = end - start;
std::cout << "elapsed time = " << diff.count() << std::endl;
} return 0;
}

在上面的代码中tokenizer是一个断词器的类模板,接受std::stringstd::wstringstd::basic_string模板实例化的类型,同时也能接受std::string_viewstd::wstring_viewstd::basic_string_view模板实例化的类型。这里采用了SFINAE的方法来约束tokenizer的模板实参必须为以上类型。如果编译环境是C++20标准,可以采用概念来约束模板实参类型。

这份代码tokenizer<std::string>运行结果是0.45秒,如果将tokenizer<std::string>替换为tokenizer<std::string_view>运行时间缩短为0.08秒,性能提升是非常明显的 。

使用 std::string_view 提升字符串处理性能的更多相关文章

  1. .NET Core中妙用unsafe减少gc提升字符串处理性能

    一.前言 昨天在群里讨论怎么样效率的把一个字符串进行反转,一般的情况我们都知道,只要对String对象进行操作,那么就会生成新的String对象,比如"1"+"2&quo ...

  2. C# 利用StringBuilder提升字符串拼接性能

    一个项目中有数据图表呈现,数据量稍大时显得很慢. 用Stopwatch分段监控了一下,发现耗时最多的函数是SaveToExcel 此函数中遍列所有数据行,通过Replace替换标签生成Excel行,然 ...

  3. dotnet 6 使用 string.Create 提升字符串创建和拼接性能

    本文告诉大家,在 dotnet 6 或更高版本的 dotnet 里,如何使用 string.Create 提升字符串创建和拼接的性能,减少拼接字符串时,需要额外申请的内存,从而减少内存回收压力 本文也 ...

  4. jQuery 做好七件事帮你提升jQuery的性能

    1. Append Outside of Loops 凡是触及到DOM都是有代价的.如果你向DOM当中附加大量的元素,你会想一次性将它们全部附加进来,而不是分多次进行.当在循环当中附加元素就会产生一个 ...

  5. java字符串格式化性能对比String.format/StringBuilder/+拼接

    String.format由于每次都有生成一个Formatter对象,因此速度会比较慢,在大数据量需要格式化处理的时候,避免使用String.format进行格式化,相反使用StringUtils.l ...

  6. Jmeter 压力测试笔记(3)--脚本调试/签名/cookie/提升吞吐量/降低异常率/提升单机并发性能

    import XXXsign.Openapi2sign;---导入jar包中的签名方法 String str1 = "12121"; ---需要被签名的字段:向开发了解需要哪些哪些 ...

  7. 提升VMware虚拟机性能招数

    在VMware虚拟机(VMware Workstation或VMware Server)中我们可以同时运行多个Guest OS,当同时在同一Host OS中运行多台虚拟机时势必会严重影响到Host O ...

  8. psutil 是因为该包能提升 memory_profiler 的性能

    python 性能分析入门指南 一点号数据玩家昨天 限时干货下载:添加微信公众号"数据玩家「fbigdata」" 回复[7]免费获取[完整数据分析资料!(包括SPSS.SAS.SQ ...

  9. 如何提升 CSS 选择器性能

    CSS 选择器性能损耗来自? CSS选择器对性能的影响源于浏览器匹配选择器和文档元素时所消耗的时间,所以优化选择器的原则是应尽量避免使用消耗更多匹配时间的选择器.而在这之前我们需要了解CSS选择器匹配 ...

  10. 七个可以提升python程序性能的好习惯,你知道吗?

    掌握一些技巧,可尽量提高Python程序性能,也可以避免不必要的资源浪费.今天就为大家带来七个可以提升python程序性能的好习惯,赶快来学习吧:. 1.使用局部变量 尽量使用局部变量代替全局变量:便 ...

随机推荐

  1. OpenAI宫斗,尘埃落定,微软成最大赢家

    周末被OpenAI董事会闹剧刷屏,ChatGPT之父Sam Altman前一天被踢出董事会,免职CEO,后一天重返OpenAI,目前结局未知. 很多同学想要围观,缺少背景知识,这里老章为大家简单介绍前 ...

  2. WPS JS宏

    WPS JS宏 1 JS宏基础 1.1 JS宏基础 1.1.1 JS录制新宏 如果在WPS表格中要编写控制表格的代码,却又不知道如何编写,那么可以使用JS录制新宏功能,接下来录制几个常用的操作: 录制 ...

  3. AutoCAD ObjectARX 二次开发(2020版)--4,使用ARX向导创建CAD二次开发项目(编程框架)--

    手动创建ObjectARX应用程序非常麻烦,在此步骤中,将介绍ObjectARX向导. 在这里,我们将使用ObjectARX向导创建我们的ObjectARX应用程序. 本节的程序的需求是,接收CAD用 ...

  4. 如何自学 PS、PR 等软件?

    学习Photoshop(PS)和Premiere Pro(PR)等软件需要一定的时间和耐心,以下是非常详细的自学指南. 第一部分:规划学习路线 1. 确定学习目标 在自学PS和PR之前,首先要明确自己 ...

  5. 分区管理工具 fdisk parted

    目录 一.fdisk工具 创建一个磁盘分区 1.虚拟机添加测试硬盘 2.创建磁盘分区 3.文件系统管理磁盘分区 4.挂载 二.parted命令 使用场景 操作命令 'help'查看命令列表 查看分区情 ...

  6. SQL动态化多个分组查询

    现有以下三张表,分别为:diqu(地区表),zhiye(职业表),info(信息表) 最基本的分组查询 1 select dqID,jbID,COUNT(1) from info group by d ...

  7. cmake的单目录和多目录的使用(Linux和Windows)

    Windows上的使用是用VS2022创建一个cmake项目 然后就可以自动生成CMakeLists.txt和对应的cpp和头文件,其中CMakeLists.txt是最关键的,后面那两个没有也行,自己 ...

  8. [CF1830E] Bully Sort

    题目描述 On a permutation $ p $ of length $ n $ , we define a bully swap as follows: Let $ i $ be the in ...

  9. NoSQL数据库与关系数据库的比较

    1.在原理方面 2.在数据规模方面 3.在数据库模式方面 4.查询效率方面: 5.在事务一致性方面: 6.在数据完整性方面: 7.在可扩展性方面: 8.在可用性方面 9.在标准化方面: 10.在技术支 ...

  10. Java中的并发队列

    1.队列 队列是一种数据结构.它有两个基本操作:在队列尾部加入一个元素,和从队列头部移除一个元素(注意不要弄混队列的头部和尾部)就是说,队列以一种先进先出的方式管理数据,如果你试图向一个 已经满了的阻 ...