购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.12 使用std::string_view代替常量字符串引用

在处理字符串时,随时都会创建临时对象,即使你可能没有真正意识到它。不过很多时候,这些临时对象都是不相关的,它们的作用只是将数据从一个地方复制到另一个地方(例如,从函数复制到它的调用者)。这也反映了一个性能问题,我们应该避免,因为它们需要内存分配和数据复制。为此,C++17标准提供了一个新的字符串类模板std::basic_string_view,它是一个指向字符串(即字符序列)的无所有权(non-owning)常量引用。在本节中,我们将了解何时使用以及如何使用这个类。

2.12.1 准备工作

std::string_view类可以在string_view头文件中的命名空间std中找到。

2.12.2 使用方式

应该使用std::string_view而不是std::string const &来向函数传递一个参数(或者从函数中返回一个值),除非代码需要调用其他接受std::string参数的函数(在这种情况下,需要进行转换):

2.12.3 工作原理

在了解新的字符串类型如何工作之前,我们先考虑一下下面的函数示例,该函数将提取不带扩展名的文件名。在C++17标准之前,这基本上就是上一节中编写函数的方法:

注意,在这个示例中,文件分隔符是反斜杠(\),与在Windows中一样。对于基于Linux的系统,必须将其更改为斜杠(/)。

get_filename()函数相对简单,它接受对std::string的常量引用,该函数提取以最后一个文件分隔符和最后一个点为界的子字符串,该字符串便是不带扩展名的文件名(且不带文件夹名)。

然而,这段代码的问题在于,它会创建一个、两个甚至更多临时对象(具体取决于编译器的优化)。函数参数是一个指向std::string的常量引用,但是该函数使用字符串字面量调用,这意味着std::string需要从字面量构造。这些临时对象需要分配和复制数据,这既消耗时间又消耗资源。在最后一个例子中,我们所要做的只是检查文件名的第一个字符是否为下划线,但为此我们至少创建了两个临时字符串对象。

std::basic_string_view类模板旨在解决这个问题。这个类模板非常类似std::basic_string,两者几乎提供相同的接口。这样做的原因是std::basic_string_view被用来替代std::basic_string的常量引用,而无须进一步修改代码。像std::basic_string一样,所有类型的标准字符都有特化版本:

类模板std::basic_string_view定义了一个对常量连续字符序列的引用。顾名思义,它表示一个视图,不能修改引用的字符序列。std::basic_string_view对象的大小相对较小,因为它所需要的只是一个指向序列中第一个字符的指针和长度。它不仅可以从std::basic_string对象构造,还可以从指针和长度构造,甚至可以从以空(null)结尾的字符序列构造(在这种情况下,需要从头遍历字符串以获取长度)。因此,std::basic_string_view类模板也可以用作多种类型字符串的公共接口(数据要求只读)。另外,想从std::basic_string_view转换为std::basic_string是不可能的。

你必须从std::basic_string_view显式地构造std::basic_string对象,如下例所示:

将std::basic_string_view传递给函数并返回std::basic_string_view,仍然会创建这种类型的临时对象,但这些是栈上的小型对象(对于64位平台,指针和大小可能只有16字节)。因此,与分配堆空间和复制数据相比,它们所需的性能成本更低。

请注意,所有主要的编译器都提供std::basic_string的实现,其中包括一个小的字符串优化。尽管实现细节有所不同,但它们通常依赖于静态分配的若干字符缓冲区(VC++和GCC 5或更新的版本为16个字符),该缓冲区不涉及堆操作,只有当字符串的大小超过该字符数时才需要堆操作。

除了与std::basic_string中相同的方法外,std::basic_string_view还有两种方法:

❍ remove_prefix():通过跳过前 N 个字符来缩小视图。

❍ remove_suffix():通过减少 N 个字符来缩小视图。

在以下示例中,使用这两个成员函数删除std::string_view开头和结尾的空格。函数的实现首先要查找第一个不是空格的元素,然后查找最后一个不是空格的元素,最后,它从末尾删除最后一个非空格字符之后的所有内容,并从开头删除第一个非空格字符之前的所有内容。该函数返回删除了首尾空格的新视图:

在使用std::basic_string_view时,必须注意两件事:不能更改视图引用的底层数据,必须管理数据的生命周期,因为视图是一个无所有权引用。

2.12.4 延伸阅读

❍ 阅读2.8节,以了解如何创建无法用标准库实现的文本工具库。 Zl0WWPF10Cb96YfdfeMN5FV/p6VZh0e05tdNy2D3zabrYoRpMlnbAKNSjNQCpWx6

点击中间区域
呼出菜单
上一章
目录
下一章
×

打开