C++字符串拼接效率比较(+=、append、stringstream、spintf)

事情起因很简单,自己的代码中使用了stringstream对象进行字符串的拼接,然后被老同事质疑效率低下。借着这个机会了解下为什么?

一、+=、append、stringsteam、sprintf四种字符串拼接方法比较

C/C++中字符串拼接的使用场景非常多,字符串拼接的方法也非常多,这里简单的比对下上述四种方法的效率。

测试方法:分别采用+=、append、stringstream、sprintf的方式来拼接字符串。s1=“aaaaa”,s2=“bbbbb”,s3=“ccccc”。内层循环将这三个字符串拼接100次;此外还有一个外层循环,循环次数自己定义(此处设为100000)。程序如下:

#include <iostream>
#include <string>
#include <sys/time.h>
#include <sstream>
#include <stdio.h>
using namespace std;
#define OUT_IN_REPEATE_NUM 100000
#define IN_REPEATE_NUM 100  //内层循环将s1、s2、s3循环拼接100次

string s1="aaaaaa";
string s2="bbbbbb";
string s3="cccccc";

void  plusTest(string& ret)
{
    for(int i=0; i<IN_REPEATE_NUM; i++)
    {
        ret += s1;
        ret += s2;
        ret += s3;
    }
}
void  appendTest(string& ret)
{
    for(int i=0; i<IN_REPEATE_NUM; i++)
    {
        ret.append(s1);
        ret.append(s2);
        ret.append(s3);
    }
}
void sprintfTest(string& ret)
{
    const size_t length=26*IN_REPEATE_NUM;
    char tmp[length];
    char* cp = tmp;
    size_t strLength=s1.length()+s2.length()+s3.length();
    for(int i=0; i<IN_REPEATE_NUM; i++)
    {
        sprintf(cp,"%s%s%s", s1.c_str(), s2.c_str(),s3.c_str());
        cp+=strLength;
    }
    ret = tmp;
}

void  ssTest(string& ret)
{
    stringstream ss;
    for(int i=0; i<IN_REPEATE_NUM; i++)
    {
        ss<<s1;
        ss<<s2;
        ss<<s3;
    }
    ret = ss.str();
}
int main() {
    string ss, plus, append, sprintf;
    struct timeval sTime, eTime;

    gettimeofday(&sTime, NULL);
    for(int i=0; i<OUT_IN_REPEATE_NUM; i++)
    {
        sprintf="";
        sprintfTest(sprintf);
    }
    gettimeofday(&eTime, NULL);
    long SprintfTime = (eTime.tv_sec-sTime.tv_sec)*1000000+(eTime.tv_usec-sTime.tv_usec); //exeTime 单位是微秒

    gettimeofday(&sTime, NULL);
    for(int i=0; i<OUT_IN_REPEATE_NUM; i++)
    {
        append="";
        appendTest(append);
    }
    gettimeofday(&eTime, NULL);
    long AppendTime = (eTime.tv_sec-sTime.tv_sec)*1000000+(eTime.tv_usec-sTime.tv_usec); //exeTime 单位是微秒

    gettimeofday(&sTime, NULL);
    for(int i=0; i<OUT_IN_REPEATE_NUM; i++)
    {
        ss="";
        ssTest(ss);
    }
    gettimeofday(&eTime, NULL);
    long SsTime = (eTime.tv_sec-sTime.tv_sec)*1000000+(eTime.tv_usec-sTime.tv_usec); //exeTime 单位是微秒

    gettimeofday(&sTime, NULL);
    for(int i=0; i<OUT_IN_REPEATE_NUM; i++)
    {
        plus="";
        plusTest(plus);
    }
    gettimeofday(&eTime, NULL);
    long PlusTime = (eTime.tv_sec-sTime.tv_sec)*1000000+(eTime.tv_usec-sTime.tv_usec); //exeTime 单位是微秒

    cout<<"PlusTime is :   "<<PlusTime<<endl;
    cout<<"AppendTime is : "<<AppendTime<<endl;
    cout<<"SsTime is :     "<<SsTime<<endl;
    cout<<"SprintfTime is :"<<SprintfTime<<endl;
    if(ss==sprintf && append==plus && ss==plus)
    {
        cout<<"result string are same!"<<endl;
    }
    else
    {
        cout<<"Different!"<<endl;
        cout<<"Sprintf: "<<sprintf<<endl;
        cout<<"ss:        "<<ss<<endl;
        cout<<"Plus:     "<<plus<<endl;
        cout<<"Append:"<<append<<endl;
    }

}

结果如下:可以看到+=、append、stringstream、sprintf四种方式在消耗的时间大致为1:1:4:2。好吧,stringstream确实好慢,人家说的是对的。

二、关于stringstream

stringstream优点:可以方便的以流运算符<<将数值以各种数据(字串、数值)写入stringstream对象,且不用担心写越界等问题;其中类型安全不会溢出的特性非常抢眼。

stringstream缺点:相对于其他方法效率较低。一方面写入时的动态内存分配需要一定的开销,另一方面其成员函数str()在去除字符串的时候会进行一次字符串的值拷贝也影响效率。

stringstream对象的构造和析构函数通常是非常消耗时间,毕竟涉及到内存的分配、对象的构造。上述测试结果也显示其效率明显低于”+=”、“append“。当然这个时间消耗也是和stringstream对象被创建了多少次密切相关的。也就是说如果能在多次转换(for循环)中重复使用同一个stringstream(而不是每次都创建一个新的对象)就还好。但是记得每次循环使用前使用clear()、str("")方法(如下)。

void* test_stringstream(void * arg)
{
	stringstream oss;
	for(int i=0;i<10000;i++)
	{
		oss.clear();这仅仅置流标记
		oss.str("");/这是才是真正清空操作
		oss << i;
	}
}

猜你喜欢

转载自blog.csdn.net/mijichui2153/article/details/118154341