【问题标题】:C++ Concatenation of Huge CStrings巨大 CStrings 的 C++ 连接
【发布时间】:2018-08-08 15:54:37
【问题描述】:

我遇到了在旧代码库中串联大量 CString 的问题。 CStrings 可以包含 base64 编码的文件,因此可能很大。在几个点上,这些 CString 像这样连接起来:

result += CString(_T("Some smaller String")) + Huge_CString + _T("Some smaller String");

这会导致多次分配,因此我们会遇到巨大的内存峰值。尽管这是在不同文件的多个线程上并行完成的。如果他们都在一起,我最终会得到“内存异常”。

处理此问题的最佳方法是什么。如果我可以减少已经有帮助的分配数量。现在我不是在寻找完美的解决方案,而是在寻找一种减少峰值的方法。

【问题讨论】:

  • A += B + C + D; 很多临时字符串。 A+=B; A+=C; A+=D; 更少(无)临时字符串。
  • operator+ 会将 C 字符串强制转换为 std::string,因此会导致如您所说的分配。也许您可以考虑使用一些 C 字符串 API,因为这些是 C 字符串,例如来自 <cstring>strcatstrncat
  • @Vivick 几乎 operator+CString 和 c-strings 重载;其余的都很好。
  • @Vivick 或者不要。基准字符串连接,包括代表您的动态内存管理,std::stringCString 与滚动您自己的并使用 strcat 和/或 strncat 之类的。 There's a reason,避免使用这些功能:长度确定。
  • @Richard Critten:对此进行了快速测试,没有区别

标签: c++ concatenation c-strings


【解决方案1】:

对于编辑大字符串,您可能希望使用非连续类型 ropeunencoded_rope - 字符串类型是线程安全的、写入时复制或插入到中间的便宜。

【讨论】:

  • 会检查的。虽然我认为我必须在那个遗留代码库中坚持使用 CString ......还是有一种简单的转换方法?
  • @DanielG 你可以用两个迭代器构造一个绳索,你可以从你的CString 获得。
【解决方案2】:

我将建议与 Remy Lebeau 基本相同的东西,但使用一些不同的功能。我不确定哪个版本的 MFC/ATL 引入了 CString::Preallocate 函数,因此您可能遇到了没有此功能的 MFC/ATL 版本。

    CString result(_T("Initial string "));
    CString prefix(_T("Prefix string:"));
    CString suffix(_T(":Suffix string"));
    CString bigString(_T("This really isn't very big."));

    auto totalLength = result.GetLength() + prefix.GetLength() + bigString.GetLength() + suffix.GetLength();

    result.Preallocate(totalLength);

    result += prefix.GetString();
    result += bigString.GetString();
    result += suffix.GetString();

对 CString::GetString 的调用可能有用也可能没用。只需将每个子字符串附加到 result,您可能会获得相同的分配行为。

【讨论】:

  • 在使用CString 方法时,我完全错过了Preallocate()。这绝对要好得多。并且operator+= 无需调用GetString() 即可工作:result += prefix; result += bigString; result += suffix; 这避免了重新计算字符或制作临时对象。
【解决方案3】:

预先分配一个具有所需连接长度的CString,然后将较小字符串中的数据复制到其内部缓冲区中,例如:

CString Huge_CString = ...;
LPCTSTR ss1 = TEXT("Some smaller String");
LPCTSTR ss2 = TEXT("Some smaller String");

int ss1_len = lstrlen(ss1);
int huge_len = Huge_CString.GetLength();
int ss2_len = lstrlen(ss2);

int concat_len = ss1_len + huge_len + ss2_len;

CString Concat_CString;
PXSTR buffer = Concat_CString.GetBufferSetLength(concat_len);
CString::CopyChars(buffer, ss1, ss1_len);
buffer += ss1_len;
CString::CopyChars(buffer, Huge_CSString.GetBuffer(), huge_len);
buffer += huge_len;
CString::CopyChars(buffer, ss2, ss2_len);
Concat_CString.ReleaseBuffer(total_len);

// use Concat_CString as needed...

【讨论】:

  • 谢谢。这就是我要找的。但我接受另一个类似的答案,因为我会选择那个。
猜你喜欢
  • 2013-03-05
  • 2020-04-30
  • 1970-01-01
  • 1970-01-01
  • 2018-09-02
  • 1970-01-01
  • 1970-01-01
  • 2010-09-18
  • 2015-11-11
相关资源
最近更新 更多