C++字符串拼接效率對比(+=、append、stringstream、sprintf)
C++字符串拼接效率對比
事情起因很簡單,自己的代碼中使用了stringstream對象進行字符串的拼接,然后被老同事質疑效率低下。借著這個機會了解下為什么?
一、+=、append、stringsteam、sprintf四種字符串拼接方法比較
C/C++中字符串拼接的使用場景非常多,字符串拼接的方法也非常多,這里簡單的比對下上述四種方法的效率。
測試方法:
分別采用+=、append、stringstream、sprintf的方式來拼接字符串。
s1=“aaaaa”,s2=“bbbbb”,s3=“ccccc”。
內層循環(huán)將這三個字符串拼接100次;此外還有一個外層循環(huán),循環(huán)次數(shù)自己定義(此處設為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 //內層循環(huán)將s1、s2、s3循環(huán)拼接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優(yōu)點:可以方便的以流運算符<<將數(shù)值以各種數(shù)據(字串、數(shù)值)寫入stringstream對象,且不用擔心寫越界等問題;其中類型安全不會溢出的特性非常搶眼。
stringstream缺點:相對于其他方法效率較低。一方面寫入時的動態(tài)內存分配需要一定的開銷,另一方面其成員函數(shù)str()在去除字符串的時候會進行一次字符串的值拷貝也影響效率。
stringstream對象的構造和析構函數(shù)通常是非常消耗時間,畢竟涉及到內存的分配、對象的構造。
上述測試結果也顯示其效率明顯低于”+=”、“append“。
當然這個時間消耗也是和stringstream對象被創(chuàng)建了多少次密切相關的。
也就是說如果能在多次轉換(for循環(huán))中重復使用同一個stringstream(而不是每次都創(chuàng)建一個新的對象)就還好。
但是記得每次循環(huán)使用前使用clear()、str("")方法(如下)。
void* test_stringstream(void * arg)
{
stringstream oss;
for(int i=0;i<10000;i++)
{
oss.clear();這僅僅置流標記
oss.str("");/這是才是真正清空操作
oss << i;
}
}字符串拼接執(zhí)行速度和內存消耗比較
public static void main(String[] args) {
long start = 0L;
long end = 0L;
System.out.println("字符串拼接執(zhí)行效率比較:");
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) + "毫秒!");
}輸出結果:
字符串拼接執(zhí)行效率比較
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,執(zhí)行一次 toString 耗時在幾微秒到幾毫秒不等
內存消耗:
+ > += > StringBuffer = StringBuilder
總結
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Qt物聯(lián)網管理平臺之實現(xiàn)數(shù)據查詢導出打印
這篇文章主要為大家介紹了如何利用Qt編寫物聯(lián)網管理平臺中數(shù)據查詢導出打印的功能,文字的示例代碼講解詳細,感興趣的可以了解一下2022-07-07
C語言中對于循環(huán)結構優(yōu)化的一些入門級方法簡介
這篇文章主要介紹了C語言中對于循環(huán)結構優(yōu)化的一些入門級方法,包括算法設計的改進來提高一些并行性等方法,要的朋友可以參考下2015-12-12

