C中的高效字符串连接

新手上路,请多包涵

我听到一些人表达了对 std::string 中“+”运算符的担忧,以及各种加快连接速度的变通方法。这些真的有必要吗?如果是这样,在 C++ 中连接字符串的最佳方法是什么?

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

阅读 1k
2 个回答

除非你真的需要效率,否则额外的工作可能不值得。 只需使用运算符 += 代替,您可能会获得更好的效率。

现在,在免责声明之后,我将回答您的实际问题……

STL 字符串类的效率取决于您使用的 STL 的实现。

您可以通过 c 内置函数手动进行连接,从而 保证效率更好地控制 自己。

为什么 operator+ 效率不高:

看一下这个界面:

 template <class charT, class traits, class Alloc>
basic_string<charT, traits, Alloc>
operator+(const basic_string<charT, traits, Alloc>& s1,
          const basic_string<charT, traits, Alloc>& s2)

可以看到每个 + 之后都会返回一个新对象。这意味着每次都使用一个新的缓冲区。如果您正在执行大量额外的 + 操作,则效率不高。

为什么可以提高效率:

  • 您是在保证效率,而不是相信委托人会为您高效地完成工作
  • std::string 类对字符串的最大大小一无所知,也不知道连接它的频率。您可能拥有这些知识,并且可以根据这些信息做事。这将导致更少的重新分配。
  • 您将手动控制缓冲区,这样您就可以确保在您不希望发生这种情况时不会将整个字符串复制到新的缓冲区中。
  • 您可以将堆栈用于缓冲区,而不是更有效的堆。
  • string + 运算符将创建一个新的字符串对象并将其返回,因此使用新的缓冲区。

实施注意事项:

  • 跟踪字符串长度。
  • 保留指向字符串结尾和开头的指针,或者只是开头并使用开头+长度作为偏移量来查找字符串的结尾。
  • 确保您存储字符串的缓冲区足够大,因此您不需要重新分配数据
  • 使用 strcpy 而不是 strcat,这样您就不需要遍历字符串的长度来查找字符串的结尾。

绳子数据结构:

如果您需要真正快速的连接,请考虑使用 绳索数据结构

原文由 Brian R. Bondy 发布,翻译遵循 CC BY-SA 4.0 许可协议

您可以尝试为每个项目保留内存:

 namespace {
template<class C>
constexpr auto size(const C& c) -> decltype(c.size()) {
  return static_cast<std::size_t>(c.size());
}

constexpr std::size_t size(const char* string) {
  std::size_t size = 0;
  while (*(string + size) != '\0') {
    ++size;
  }
  return size;
}

template<class T, std::size_t N>
constexpr std::size_t size(const T (&)[N]) noexcept {
  return N;
}
}

template<typename... Args>
std::string concatStrings(Args&&... args) {
  auto s = (size(args) + ...);
  std::string result;
  result.reserve(s);
  return (result.append(std::forward<Args>(args)), ...);
}

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

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