c++中字符串连接的开销

c++ overhead from string concatenation

本文关键字:开销 连接 字符串 c++      更新时间:2023-10-16

我正在从ifstream中读取随机ascii文本文件。我需要能够把整个消息变成字符串类型的字符解析。我目前的解决方案是有效的,但是我认为我在更长的文件上浪费了处理时间,因为我使用了如下的等效物:

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

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

我读过这个线程听起来几乎适用,但仍然让我不确定;

有什么建议吗?

真正的问题是您不知道提前的完整大小,所以您不能适当地分配内存。我希望您得到的性能影响与此有关,而不是与string的连接方式有关,因为它在标准库中有效地完成了。

因此,我建议推迟连接,直到您知道最终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;
}

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

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

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

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

如果您进行概要分析并发现这仍然是一个瓶颈,那么您可以自己使用std::string::reserve并使用典型的数量。

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

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;
}