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

 更新时间:2023年08月01日 08:41:27   作者:焱齿  
这篇文章主要介绍了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

总结

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

相关文章

  • C语言版扫雷小游戏

    C语言版扫雷小游戏

    这篇文章主要为大家详细介绍了C语言版的扫雷小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • C语言二维数组应用之扫雷游戏

    C语言二维数组应用之扫雷游戏

    这篇文章主要为大家详细介绍了C语言二维数组应用之扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • C++中的六个函数

    C++中的六个函数

    本文给大家介绍了C++中的六个函数,非常不错,具有一定的参考借鉴价值,需要的朋友参考下吧
    2018-05-05
  • C++中的多态与多重继承实现与Java的区别

    C++中的多态与多重继承实现与Java的区别

    这篇文章主要介绍了C++中的多态与多重继承实现与Java的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • C++生成随机数的实现代码

    C++生成随机数的实现代码

    这篇文章主要介绍了C++生成随机数的实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • 使用C语言实现最小生成树求解的简单方法

    使用C语言实现最小生成树求解的简单方法

    这篇文章主要介绍了使用C语言实现最小生成树求解的简单方法,包括Prim算法和Kruskal算法的两种求解方式,需要的朋友可以参考下
    2015-08-08
  • C/C++经典实例之模拟计算器示例代码

    C/C++经典实例之模拟计算器示例代码

    最近在看到的一个需求,本以为比较简单,但花了不少时间,所以下面这篇文章主要给大家介绍了关于C/C++经典实例之模拟计算器的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-10-10
  • 基于Matlab实现俄罗斯方块游戏

    基于Matlab实现俄罗斯方块游戏

    俄罗斯方块是一个最初由阿列克谢帕吉特诺夫在苏联设计和编程的益智类视频游戏。本文将利用Matlab实现这一经典的小游戏,需要的可以参考一下
    2022-03-03
  • M1 Macbook vscode C++ debug调试实现

    M1 Macbook vscode C++ debug调试实现

    本文主要介绍了M1 Macbook vscode C++ debug调试,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • 利用Qt实现可扩展对话框的示例代码

    利用Qt实现可扩展对话框的示例代码

    可扩展对话框通常用于用户对界面有不同要求的场合。当供高级用户使用或需要更多信息时,可通过某种方式的切换显示完整对话窗体(扩展窗体)。本文将用Qt实现可扩展对话框,需要的可以参考一下
    2022-06-06

最新评论