将 QStringView 转换为 std::string 最有效的方法是什么?

Ben*_*uch 2 c++ qt stdstring c++20 qt6

我有一个函数,它的参数为QStringView. 除此之外,这必须转换为std::string. 有这个QString功能。toStdString()有没有办法避免潜在昂贵的中间步骤 via QString

Yak*_*ont 5

字符编码之间的转换很难正确进行。QString 存储 16 位 UTF-16。 toStdString使用中间字节数组将其重新编码为 utf-8 toUtf8

QStringView也有toUtf8返回 aQByteArray并具有与 相同的保证QString

std::string toStdString( QStringView view ) {
  auto bytes = view.toUtf8(); // allocates and converts.
  return {bytes.constData(), bytes.length()}; // copies to a std::string
}
Run Code Online (Sandbox Code Playgroud)

与天真的相比,这会减少 1 个内存副本

std::string toStdString( QStringView view ) {
  return QString(view).toStdString();
}
Run Code Online (Sandbox Code Playgroud)

理论上,有 1 个中间内存副本也可以删除;您可以直接从 UTF16 QStringView 数据转换为std::string.

std::string toStdString( QStringView view ) {
  auto toUtf8 = QStringEncoder(QStringEncoder::Utf8);
  auto space = toUtf8.requiredSpace(view.length());
  std::string retval;
  // make a string of all nulls:
  retval.resize(space+1); // +1 probably not needed
  // Ideally use C++23's `resize_and_overwrite`
  // instead of `resize` above.  Without that, on large (>1k)
  // strings other solutions are faster.

  // output the UTF8 into the std::string:
  char* end = toUtf8.appendToBuffer(retval.data(), view);
  // Strip the nulls logically from the returned string:
  retval.resize(end-retval.data());
  return retval;
}
Run Code Online (Sandbox Code Playgroud)

这是为了避免中间缓冲区分配。它可能不正确并且存在错误,但设计是合理的。

理论上,一个更疯狂的系统可以在创建输出缓冲区之前(或在您创建输出缓冲区时)计算出 UTF16 所需的实际空间。

(由于 @BenjaminBuch 在另一个答案中的出色分析而添加了 resize_and_overwrite 优化)。