C++ 通过字符串来计算长度比移动字符串几次需要更长的时间?

C++ 通过字符串来计算长度比移动字符串几次需要更长的时间?,c++,string,memory-reallocation,C++,String,Memory Reallocation,我编写了以下两个函数。在第二个函数中,我使用了reserve() 我在VisualStudio中使用了发布模式和这个CPU分析器来计算时间。在第二个函数中,重新分配发生33次。所以我的问题是:真的吗?将一个长度的字符串移动到计数长度比将此字符串移动33次需要更长的时间 string commpres2(string str) { string strOut; int count = 0; for (int i = 0; i < str.length(); ++i)

我编写了以下两个函数。在第二个函数中,我使用了
reserve()

我在VisualStudio中使用了发布模式和这个CPU分析器来计算时间。在第二个函数中,重新分配发生33次。所以我的问题是:真的吗?将一个长度的字符串移动到计数长度比将此字符串移动33次需要更长的时间

string commpres2(string str)
{
    string strOut;
    int count = 0;
    for (int i = 0; i < str.length(); ++i)
    {
        ++count;
        if (i < str.length() - 1)
        {
            if (str[i + 1] != str[i])
            {
                strOut += str[i];
                strOut += to_string(count);
                count = 0;
            }
        }
        else
        {
            strOut += str[i] + to_string(count);
        }
    }
    return strOut.length() < str.length() ? strOut : str;
}

string commpres3(string str)
{
    int compressedLength = 0;
    int countConsecutive = 0;
    for (int i = 0; i < str.length(); ++i)
    {
        ++countConsecutive;
        if (i + 1 >= str.length() || str[i] != str[i + 1]) 
        {
            compressedLength += 1 + 
                to_string(countConsecutive).length();
            countConsecutive = 0;
        }
    }
    if (compressedLength >= str.length())
        return str;
    string strOut;
    strOut.reserve(compressedLength);
    int count = 0;
    for (int i = 0; i < str.length(); ++i)
    {
        ++count;
        if (i < str.length() - 1)
        {
            if (str[i + 1] != str[i])
            {
                strOut += str[i];
                strOut += to_string(count);
                count = 0;
            }
        }
        else
        {
            strOut += str[i] + to_string(count);
        }
    }
    return strOut;
}

int main()
{
    string str = "aabcccccaaa";

    //str.size ~ 11000000;
    for (int i = 0; i < 20; ++i)
        str += str;
    commpres2(str); //107ms //30,32% CPU
    commpres3(str); //147ms //42,58% CPU
}
string commpres2(string str)
{
弦乐;
整数计数=0;
对于(int i=0;i=str.length()| str[i]!=str[i+1])
{
压缩长度+=1+
to_字符串(countContinuous).length();
连续计数=0;
}
}
如果(压缩长度>=str.length())
返回str;
弦乐;
压缩储备(压缩长度);
整数计数=0;
对于(int i=0;i
第二个函数比第一个函数要做更多的工作,因此当然需要更长的时间。对代码进行分析应该会准确地告诉您代码在哪里花费时间。例如,第一个函数最多循环一次
str
,但第二个函数可能循环两次相同的
str
,根据定义,这需要更长的时间

您也没有从第二个函数中删除所有内存分配
to_string()
分配内存,在调用
reserve()
之前和之后都要多次调用它。消除所有
to_string()
分配相当简单,使用
std::snprintf()
到本地缓冲区,然后
std::string::append()
将该缓冲区添加到输出
std::string

您可以放弃所有的预计算,只保留整个
str
长度,即使最后没有使用所有的内存。在更糟糕的情况下,您不会使用超过原始长度的
str
长度(根本不可能进行压缩):

inline int to_buffer(size_t number,char*buf,size_t bufsize)
{
返回snprintf(buf,bufsize,“%zu”,数字);
}
字符串commpres3(常量字符串和字符串)
{
字符串::size_type strLen=str.length();
弦乐;
斯特朗保留地(斯特伦);
大小\u t计数=0;
char-buf[25];
对于(字符串::大小\类型i=0;i=strLen)
返回str;
}
回程行程;
}
或者,如果必须进行预计算,可以将第一组
to_string()
调用替换为返回所需长度的其他调用,而无需动态分配内存(用于ideas)。在计算要保留的大小时,实际上不需要将整数123转换为分配的字符串“123”,就可以知道它将占用3个字符

inline int to_buffer(size_t number,char*buf,size_t bufsize)
{
返回snprintf(buf,bufsize,“%zu”,数字);
}
内联整数到缓冲区长度(大小\u t编号)
{
返回到_缓冲区(number,nullptr,0);
}
字符串commpres3(常量字符串和字符串)
{
字符串::size_type strLen=str.length();
字符串::大小\类型压缩长度=0;
大小=0;
对于(字符串::大小\类型i=0;i=strLen)
返回str;
弦乐;
压缩储备(压缩长度);
大小\u t计数=0;
char-buf[25];
对于(字符串::大小\类型i=0;i
33内存分配与