如何有效地获取\`std::string\`的子字符串的\`string_view\`

新手上路,请多包涵

使用 http://en.cppreference.com/w/cpp/string/basic_string_view 作为参考,我认为没有办法更优雅地做到这一点:

 std::string s = "hello world!";
std::string_view v = s;
v = v.substr(6, 5); // "world"

更糟糕的是,这种幼稚的方法是一个陷阱,并且会留下 v 对临时的悬空引用:

 std::string s = "hello world!";
std::string_view v(s.substr(6, 5)); // OOPS!

似乎记得 标准库中可能会添加一个以将子字符串作为视图返回的内容:

 auto v(s.substr_view(6, 5));

我可以想到以下解决方法:

 std::string_view(s).substr(6, 5);
std::string_view(s.data()+6, 5);
// or even "worse":
std::string_view(s).remove_prefix(6).remove_suffix(1);

坦率地说,我认为这些都不是很好。现在我能想到的最好的事情就是使用别名来简单地让事情变得不那么冗长。

 using sv = std::string_view;
sv(s).substr(6, 5);

原文由 sehe 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 588
1 个回答

有自由功能路线,但除非您还为 std::string 提供重载,否则这是一个蛇坑。

 #include <string>
#include <string_view>

std::string_view sub_string(
  std::string_view s,
  std::size_t p,
  std::size_t n = std::string_view::npos)
{
  return s.substr(p, n);
}

int main()
{
  using namespace std::literals;

  auto source = "foobar"s;

  // this is fine and elegant...
  auto bar = sub_string(source, 3);

  // but uh-oh...
  bar = sub_string("foobar"s, 3);
}

恕我直言,string_view 的整个设计是一场恐怖秀,它将带我们回到一个充满段错误和愤怒客户的世界。

更新:

即使为 std::string 添加重载也是一场恐怖表演。看看你是否能发现微妙的段错误定时炸弹……

 #include <string>
#include <string_view>

std::string_view sub_string(std::string_view s,
  std::size_t p,
  std::size_t n = std::string_view::npos)
{
  return s.substr(p, n);
}

std::string sub_string(std::string&& s,
  std::size_t p,
  std::size_t n = std::string::npos)
{
  return s.substr(p, n);
}

std::string sub_string(std::string const& s,
  std::size_t p,
  std::size_t n = std::string::npos)
{
  return s.substr(p, n);
}

int main()
{
  using namespace std::literals;

  auto source = "foobar"s;
  auto bar = sub_string(std::string_view(source), 3);

  // but uh-oh...
  bar = sub_string("foobar"s, 3);
}

编译器在这里没有发现任何警告。我确信代码审查也不会。

我之前说过,我会再说一遍,以防 c++ 委员会的任何人在看, 允许从 std::stringstd::string_view 的隐式转换是一个可怕的错误,它只会使 C++ 声名狼藉

更新

在 cpporg 留言板上提出了 string_view 的这个(对我而言)相当惊人的属性后,我的担忧得到了冷漠。

这个小组的一致意见是 std::string_view 绝对不能从函数中返回,这意味着我上面的第一个提议是错误的形式。

当然,编译器无法帮助捕捉意外发生的时间(例如通过模板扩展)。

因此, std::string_view 应该非常小心地使用,因为从内存管理的角度来看,它等同于指向另一个可能不再存在的对象状态的可复制指针。但是,它在所有其他方面看起来和行为都像值类型。

因此代码如下:

 auto s = get_something().get_suffix();

get_suffix() 返回 std::string --- 时是安全的(通过值或引用)

但是如果 get_suffix() 被重构为返回 std::string_view ,则为 UB。

在我看来,这意味着任何使用 auto 存储返回字符串的用户代码都会中断,如果他们调用的库被重构为返回 std::string_view 代替 std::string const& .

所以从现在开始,至少对我来说,“几乎总是自动”将不得不变成“几乎总是自动,除非它是字符串”。

原文由 Richard Hodges 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题