Bootstrap

【C++】C++ 17简单上手(2)——string_view

什么是string_view

std::string_view是C++ 17标准中新加入的类,正如其名,它提供一个字符串的视图,即可以通过这个类以各种方法“观测”字符串,但不允许修改字符串。由于它只读的特性,它并不真正持有这个字符串的拷贝,而是与相对应的字符串共享这一空间。即——构造时不发生字符串的复制。同时,你也可以自由的移动这个视图,移动视图并不会移动原定的字符串。

正因这些特性,当你不需要改变字符串时,应当抛弃原来使用的const string而采用新的string_view,这样可以避免多余的字符串拷贝。

构造

std::string_view允许通过C风格的字符串、字符串字面量、std::string或者其他的string_view进行构造。在构造的同时允许指定“大小”。

const char *cstr_pointer = "pointer";
char cstr_array[] = "array";
std::string stdstr = "std::string";

std::string_view
    sv1(cstr_pointer, 5),  // 使用C风格字符串-指针构造,并指定大小为5
    sv2(cstr_array),    // 使用C风格字符串-数组构造
    sv3("123456", 4),   // 使用字符串字面量构造,并指定大小为4
    sv4(stdstr),        // 使用std::string构造
    sv5("copy"sv);      // 使用拷贝构造函数构造(sv是std::string_view字面量的后缀)

std::cout
    << sv1 << endl    // point
    << cstr_pointer << endl // pointer
    << sv2 << endl    // array
    << sv3 << endl    // 1234
    << sv4 << endl    // std::string
    << sv5 << endl;   // copy

一些常见操作

如同std::string一样,string_view支持迭代器,也同样支持获取元素等操作,标准库也为它编写了相关的istreamostream的运算符重载形式,并重载了swap函数

// using namespace std;
string_view sv("123456789", 5);

// 支持Range-based for
for (auto i : sv) {
    cout << i << ' ';
}
// 支持begin/end, cbegin/cend, rbegin/rend, crbegin/crend迭代器
for (auto it = sv.crbegin(); it != sv.crend(); ++it) {
    cout << *it << ' ';
}

cout << sv.at(0) << ' ' << sv[1]; // 输出指定位置上的字符
cout << sv.front();  // 输出首位字符
cout << sv.back();   // 输出末位字符
cout << sv.size() << ' ' << sv.length(); // 输出视图中的字符串长度
cout << sv.data();   // 输出字符串存储的位置
cout << sv.empty();  // 输出字符串是否为空
cout << sv.substr(0, 2); // 输出字符串的子串(用法与string的一致)

string_view sv2("12345");
cout << (sv == sv2 ? "true" : "false"); // 支持同string一样的各种比较符号

更改视图的大小

类中提供了两个函数remove_suffix(从后面缩减大小)和remove_prefix(从前方缩减大小),可以缩减视图的大小。

string_view sv("123456789");
sv.remove_suffix(1);    // 现在sv中为:12345678, sv的大小为8
sv.remove_prefix(2);    // 现在sv中为: 345678, sv的大小为6

字符串查找

如同std::string一样,视图也提供了在字符串中进行查找的算法,并计划在C++ 20中提供starts_withends_with函数。这些函数的用法与std::string中的并无二致,此处不再赘述。

生命周期

由于string_view并不真正的持有字符串,所以若视图所引用的字符串区域已经被销毁,那么对应的,视图也会相应的失效。无法起到作用,下面的代码是一个例子,在这个例子中,将无法按照预期输出Example

std::string_view getView() {
    char ar[] = "Example";
    return { ar };
}

int main()
{
    std::cout << getView() << std::endl;
    return 0;
}
;