C++ 17 新特性 std::string_view

c++ 17提供了一个新的性能工具std::string_view。它有着类似std::string的接口易于使用,但是又不拥有字符串的内存,避免了很多拷贝内存操作,性能接近原始c字符串指针。

  char text[]{"hello"};
  std::string str{text};
  std::string more{str};

  std::string_view svtext{"hello"};
  std::string_view svstr{svtext};
  std::string_view svmore{svstr};

如上代码:

因为std::string_view不拥有内存,避免了很多次内存数据拷贝。

其实std::string_view本身很简单,它只有两个成员变量,指向内存的指针和可以访问到的长度。它对它指向的内存是只读的,std::string_view的任何方法都不会改变执行的内存。

  std::string raw("Peach");
  std::string_view str{ raw };

  std::cout << str << std::endl;

  str.remove_prefix(1);
  std::cout << str << std::endl;

  str.remove_suffix(2);
  std::cout << str << std::endl;

  std::cout << raw << std::endl;

输出:
Peach
each
ea
Peach

同样,如果执行的内存本身自己改变了,就能里面反应到std::string_view里面,如下所示:

  char arr[]{ "Gold" };
  std::string_view str{ arr };

  std::cout << str << '\n'; // Gold

  // Change 'd' to 'f' in arr
  arr[3] = 'f';

  std::cout << str << '\n'; // Golf

输出:
Gold
Golf

此外,std::string_view还能与非null-terminated 字符串配合使用:

  // No null-terminator.
  char vowels[]{'a', 'e', 'i', 'o', 'u'};

  // vowels isn't null-terminated. We need to pass the length manually.
  // Because vowels is an array, we can use std::size to get its length.
  std::string_view str{vowels, std::size(vowels)};

  // This is safe. std::cout knows how to print std::string_views.
  std::cout << str << std::endl;

std::string_view并不拥有所观察的字符串的内存,因此需要对内存多加小心:

std::string_view AskForName() {
  std::cout << "What's your name?\n";

  std::string str{};
  std::cin >> str;

  std::string_view view{str};

  std::cout << "Hello " << view << '\n';

  return view;
}

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

上面代码返回了view,但是view所观察的局部变量str离开函数就销毁了,继续使用view会导致未定义的行为。

std::string_view对应的是string,std::string_view背后是basic_string_view模板,因此它有几种字符串变种:

std::string_view        std::basic_string_view<char>
std::u8string_view      std::basic_string_view<char8_t> (C++20)
std::u16string_view     std::basic_string_view<char16_t>
std::u32string_view     std::basic_string_view<char32_t>
std::wstring_view       std::basic_string_view<wchar_t>

下面是网上有人对比string_view和string性能,看起string_view性能还是有很大提升的,因此我们尽可能多的场合去使用string_view。

string_view和string性能对比

参考: