【问题标题】:CString += operator performance issuesCString += 运算符性能问题
【发布时间】:2014-04-26 14:08:29
【问题描述】:

我正在处理一个较旧的 MFC/C++ 项目,该项目使用 MFC 的 CString 类来处理字符串来解析大型文本文件。我注意到在解析过程中,有很多小部分添加到整个大型 CString 对象中:

//'strContainer' = CString
//'tag' = CString of a much smaller size
strContainer += L"<" + tag + L">";

strContainer 变量达到某个较大的大小时,上面的运算符似乎会降低 CString 的整体性能。我认为这是因为+= 运算符经常重新分配内存。

所以我很好奇,有什么办法可以改善这一点吗?

PS1。我不知道预先分配结果字符串的大小。

PS2。由于项目本身的复杂性,我必须坚持使用 CString。 (或者,我无法切换到 Boost 或其他更新的实现。)

【问题讨论】:

  • 实际上,+= 可能是最快的部分。性能问题可能是临时工的+。因此,请执行三遍+=,看看是否会有所不同。
  • @MooingDuck:衡量这种性能的问题在于,单个操作员本身不会引起人类注意。当我在解析方法中运行数千个它们时,它就会变得可见。无论哪种情况,我都很肯定它是执行内存重新分配的CString 运算符之一。我总结它是因为它的性能随着CString 变量的大小呈指数下降。
  • 即使您无法预先分配最佳金额,您仍然可以预先分配足够的金额来满足您的大部分情况。与第一次编写程序时相比,内存问题可能要少得多。
  • 这段代码编译是否经过优化(不是调试模式?)。我编写了处理非常大的字符串的代码(诚然不是 CString,但我怀疑它效率低下)。在调试版本中,由于各种额外的检查,几乎可以肯定它非常慢。
  • @c00000fd:只需在开始追加之前调用Preallocate,并为其提供一个足以容纳 95% 数据的数字。超级容易。 (另外 5% 会像以前一样重新分配,但通常只分配一次,而不是 10 次)

标签: c++ performance mfc cstring


【解决方案1】:

使用std::string+= 通常非常快,因为它可以将字节复制到已分配的缓冲区中。通常,L"&lt;" + tag + L"&gt;"; 将需要三个或更多内存分配,如果您只是将那行代码替换为三个+=,那么这是完全没有必要的。此外,如果您让 Visual Studio 为您启动程序,即使是发布版本,分配也会真的很慢。在没有 Visual Studio 的情况下手动运行您的程序,看看是否能解决您的性能问题。

我深入研究了 MFC 源代码。 (又挖又挖...)发现ATL::CSimpleStringT::PrepareWrite2(int nLength)会成倍增长(每次分配大1.5倍,完全正常,std::string是一样的,除了...
如果MFC字符串超过1G,之后每次分配只增加1M。

所以有两个条件: 如果strContainer超过1G,你应该手动预留内存(Preallocate大量字节。不一定要精确,甚至大于实际数字。)。
否则,只需将+ 替换为+=

【讨论】:

  • 很好的发现。谢谢。虽然我正在使用的字符串大小约为 50 MB。少于您建议的1GB。我正在一台配备 Intel i7 CPU 和 16GB RAM 的快速 Windows 8 机器上运行它。
  • 在这种情况下,第一个选项。将+ 替换为+=,并使用未附加的Visual Studio 进行测试。
  • 嗯...好的。尽管即使考虑更改现有的解析逻辑也让我不寒而栗。如果我可以先通过预分配解决它会很好......
  • 在 CString 中使用预分配的最简单方法是使用给定长度的 GetBuffer。只要您不对缓冲区进行中间处理,就不需要 ReleaseBuffer。在预分配缓冲区时,还使用三倍 += 而不是临时 CString 会更胖。
  • @xMRi:我没有立即看到strContainer.GetBuffer(30)strContainer.Preallocate(30) 更容易或更直观,但你是对的,在我写下这个答案之前,这就是我的方式众所周知
猜你喜欢
  • 2021-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-24
  • 2012-09-04
  • 2010-12-31
  • 2020-11-06
  • 1970-01-01
相关资源
最近更新 更多