4

我正在从 ifstream 中读取随机 ascii 的文本文件。我需要能够将整个消息放入字符串类型以进行字符解析。我当前的解决方案有效,但我认为我正在使用等效的方法在更长的文件上谋杀处理时间:

std::string result;

for (std::string line; std::getline(std::cin, line); )
{
    result += line;
}

我担心与这样的连接字符串相关的开销(这种情况发生了几千次,消息长达数千个字符)。我过去几天一直在浏览不同的潜在解决方案,但没有什么是非常合适的......我不知道提前消息的长度,所以我不认为使用动态大小的字符数组是我的答案.

我通读了这个听起来几乎适用但仍然让我不确定的SO 线程;

有什么建议么?

4

4 回答 4

1

问题实际上是您不提前知道完整大小,因此您无法适当地分配内存。我希望您获得的性能影响与此有关,而不是与strings 连接的方式有关,因为它在标准库中有效地完成了。

因此,我建议推迟连接,直到您知道 final 的完整大小string。也就是说,您首先将所有字符串存储在一个大vector文件中:

using namespace std;
vector<string> allLines;
size_t totalSize = 0;
// If you can have access to the total size of the data you want
// to read (size of the input file, ...) then just initialize totalSize
// and use only the second code snippet below.
for (string line; getline(cin, line); )
{
    allLines.push_back(line);
    totalSize += line.size();
}

然后,您可以string提前知道它的大小来创建您的大:

string finalString;
finalString.reserve(totalSize);
for (vector<string>::iterator itS = allLines.begin(); itS != allLines.end(); ++itS)
{
    finalString += *itS;
}

不过,我应该提一下,只有在遇到性能问题时才应该这样做。不要尝试优化不需要的东西,否则会使程序复杂化而没有明显的好处。我们需要优化的地方通常是违反直觉的,并且可能因环境而异。因此,只有在您的分析工具告诉您需要时才这样做。

于 2013-04-05T22:06:55.620 回答
0

您正在为文件中的每一行复制结果数组(当您展开结果时)。而是预先分配结果并以指数方式增长:

std::string result;
result.reserve(1024); // pre-allocate a typical size

for (std::string line; std::getline(std::cin, line); )
{
    // every time we run out of space, double the available space
    while(result.capacity() < result.length() + line.length())
        result.reserve(result.capacity() * 2);

    result += line;
}
于 2013-04-05T21:55:25.610 回答
0

如果您知道文件大小,请使用 result 的成员函数 'reserve()' 一次。

于 2013-04-05T21:47:00.727 回答
0

我太困了,无法为您整理任何可靠的数据,但最终,在不提前知道大小的情况下,您总是不得不做这样的事情。事实上,您的标准库实现足够智能,可以相当巧妙地处理字符串大小调整。(尽管事实上 没有指数增长保证std::string,但 有std::vector。)

因此,尽管您可能会在前 50 次左右的迭代中看到不需要的重新分配,但一段时间后,重新分配的块变得如此之大,以至于重新分配变得很少见。

如果您分析并发现这仍然是一个瓶颈,也许使用std::string::reserve一个典型的数量。

于 2013-04-05T21:48:33.723 回答