C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++字符串拼接效率

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

作者:焱齿

这篇文章主要介绍了C++字符串拼接效率对比(+=、append、stringstream、sprintf),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

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

总结

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

您可能感兴趣的文章:
阅读全文