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. Markdown 跳转到本文章标题

    一.只可以在Markdown文件中跳转 1.因为 Markdown 文件标题就是 Markdown 一种锚点 任何级别的标题可以直接作为锚点目标.如果标题比较固定(不是经常改来改去),可以直接使用标题 ...

  2. 常用sql语句(不定时更新)

    --查询数据库所有表名与表说明 select a.name tableName, b.value tableComment from sysobjects a LEFT JOIN sys.extend ...

  3. mysql的begin end嵌套

    这个教程基本很少,因为这个很简单,但又会让(新手)人难以完成这嵌套. 为了方便读者理解,我把不需要嵌套的也嵌套起来了.(就比如下面这几行代码) delimiter $$ drop procedure ...

  4. Netty源码学习8——从ThreadLocal到FastThreadLocal(如何让FastThreadLocal内存泄漏doge)

    系列文章目录和关于我 一丶引入 在前面的netty源码学习中经常看到FastThreadLocal的身影,这一篇我们将从ThreadLocal说起,来学习FastThreadLocal的设计(< ...

  5. 吉特日化MES & 再谈原料标签

    在前面之前提到的标签的选择和设计,原料标签可以做到如下几点:     1 原料标签是一物一码还是一码多物:在美妆类的原料建议原料标签采用一物一码,对于大液洗之类的产品原料如果能够做到一物一码最佳,但是 ...

  6. [ARC132E] Paw

    题目链接 考虑最后形态,一定是有某一个区间 \([l,r]\) 保持初始的样子, \(l\) 前面都是 <,\(r\) 后面都是 >. 这个区间一定是某两个相邻圆点的位置.设 \(f_i\ ...

  7. MyBatisPlus简介

    MyBatisPlus特性 国内的一个网站 网站地址简介 | MyBatis-Plus (baomidou.com)

  8. 三种方式查询三级分类Tree

    话不多说,直接上代码 方式一:for循环嵌套一下 /** * 查询三级分类 * * @return */ @Override public List<GoodsType> findNode ...

  9. pytorch学习笔记——加载checkpoint时,程序报错,存在GPU和CPU不同步的情况

    当我们需要加载之前训练的checkpoint的时候,有时候会发现之前能训练的代码无法继续训练. 这时候很有可能加载优化器的步骤在加载模型前面,这样可能会导致优化器的参数仍然在CPU上,因此代码需要由原 ...

  10. EF Core助力信创国产数据库

    前言 国产数据库作为国产化替代的重要环节,在我国信创产业政策的指引下实现加速发展,我们国产数据库已进入百花齐放的快速发展期,相信接触到涉及到政府类等项目的童鞋尤为了解,与此同时我们有一部分也在使用各种 ...