目录
  • C++字符串拼接效率对比
    • 一、+=、append、stringsteam、sprintf四种字符串拼接方法比较
    • 二、关于stringstream
  • 字符串拼接执行速度和内存消耗比较
    • 字符串拼接执行效率比较
  • 总结

    C++字符串拼接效率对比

    事情起因很简单,自己的代码中使用了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;
    	}
    }

    字符串拼接执行速度和内存消耗比较

    public static void main(String[] args) {
            long start = 0L;
            long end = 0L;
            System.out.println("字符串拼接执行效率比较:");
            String s1 = "";
            start = System.currentTimeMillis();
            for (int i = 0; i < 100000; i++) {//十万次
            	s1 = s1 + "a";
            }
            end = System.currentTimeMillis();
            System.out.println("1、+ 方式拼接10万次耗时:" + (end - start) + "毫秒!");
            String s2 = "";
            start = System.currentTimeMillis();
            for (int i = 0; i < 100000; i++) {//十万次
            	s2 += "b";
            }
            end = System.currentTimeMillis();
            System.out.println("2、+= 方式拼接10万次耗时:" + (end - start) + "毫秒!");
            StringBuffer bf = new StringBuffer();
            start = System.currentTimeMillis();
            for (int i = 0; i < 10000000; i++) {//千万次
            	bf.append("c");
            }
            end = System.currentTimeMillis();
            System.out.println("3、StringBuffer.append 方式拼接1000万次耗时:" + (end - start) + "毫秒!");
            StringBuilder bl=new StringBuilder();
            start = System.currentTimeMillis();
            for (int i = 0; i < 10000000; i++) {//千万次
            	bl.append("d");
            }
            end = System.currentTimeMillis();
            System.out.println("4、StringBuilder.append 方式拼接1000万次耗时:" + (end - start) + "毫秒!");
    	}

    输出结果:

    字符串拼接执行效率比较

    1、+ 方式拼接10万次耗时:4561毫秒!

    2、+= 方式拼接10万次耗时:4491毫秒!

    3、StringBuffer.append 方式拼接1000万次耗时:189毫秒!

    4、StringBuilder.append 方式拼接1000万次耗时:141毫秒!

    解释:+ 方式本质是 s = new StringBuilder(s).append("a") .toString();

    耗时间的地方不是 append,而是 toString,执行一次 toString 耗时在几微秒到几毫秒不等

    内存消耗:

    + > += > StringBuffer = StringBuilder

    总结

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持本网站。

    您可能感兴趣的文章:

    • C++中string使用+号与int拼接方式
    • 详解C++ OpenCV实现图像拼接的原理及方法
    • C++ OpenCV实战之图像全景拼接
    • C++实现批量图片拼接
    • 使用c++实现OpenCV图像横向&纵向拼接
    • 基于C++的摄像头图像采集及拼接程序的简单实现
    • C++ 两个vector对象拼接方式
    • 关于c++11与c风格路径拼接的速度对比
    • C++使用join拼接字符串的技巧
    • C++整数拼接技巧大揭秘