C/C++&Java 字符串拼接效率对比
C/C++拼接字符串的方式很多,尤其是所谓的”VC++”语言(不应该称其为语言,但是很多使用VC++的程序员却把它变成了VC++语言即微软血统的C++语言)中这种方式又变多一些。在Windows下的Visual C++中很多的程序员习惯使用微软MFC中CString 。虽然使用MFC编程时使用CString来处理字符串的确有着与MFC库配合的便利。但是在开发中如果并没有用到MFC的时候我建议还使用 Standard C++的字符串。好处很多首先它是标准的意味着你使用它(std::string, std::wstring)来处理字符串。并且你的程序没有使用与具体操作系统相关的API (或使用了跨平台的相关类库代替)。 那么意味着你的代码在有对应平台的并且符合C++标准的编译器下可以直接编译通过。也意味着你的程序具备较好的跨平台能力。另外在性能方面也较为出色。下面测试了一下在VC++2008中各种字符串拼接方式的性能对比。当然这里面有有预分配方式的,测试程序中最后会根据每一项的耗时进行排序,当然排序的结果需要看是否采用预分配方式。当然C++ std::string, std::wstring中有一些提高效率的机制(在非预分配方式下)。然后又在Java中测试了一下字符Java的StringBuffer及StringBuilder字符串拼接效率也很不错。最后测试的结果有助于指导我们使用最高效的方式处理字符处拼接。
字符串拼接测试方式分别是:
1. C语言在预分配内存上的strcpy函数
2. C语言在预分配内存上的 memcpy函数
3. C++中std::string的 append函数
4. C++中std::string 的 operator+=
5. C++中std::ostringstream的 operator<<
6. C++中std::string使用事先预分配(调用 reserve函数)
7. MFC中CString的Append函数
8. MFC中CString的operator+=
以下测试代码:
注:在 const int TEST_TIMES = 9000000;时C的memcpy使用16-32 ms(毫秒) std::string 也在 1000 ms(毫秒)左右。由于其他的方式耗时过长因此将 TEST_TIMES = 90000次 在Java中普通的String也是如此.
#include "stdafx.h"
#include <string>
#include <sstream>
#include <iostream>
#include <cassert>
#include <cstring>
#include <ctime>
#include <vector>
#include <algorithm>
#include <afxwin.h>
using namespace std;
const int TEST_TIMES = 90000;
const char APPEND_CONTENT[] = "cppmule";
const int PREALLOCATE_SIZE = strlen(APPEND_CONTENT) * TEST_TIMES + 1;
class Statistic {
public:
string item;
int used;
friend inline ostream & operator << (ostream & os, const Statistic &stat) {
os << "item: " << stat.item << endl
<< "used: " << stat.used << " ms." << endl << endl;
return os;
}
inline bool operator>(const Statistic& stat) {
return (used > stat.used);
}
inline bool operator<(const Statistic& stat) {
return (used < stat.used);
}
};
vector<Statistic> g_statistics;
#define BEGIN_TICK() \
clock_t start = clock();
#define END_AND_PRINT_TICK(info) \
clock_t used = clock() - start; \
Statistic stat; \
stat.item.assign(info); \
stat.used = used; \
g_statistics.push_back(stat); \
cout << info << " Used: " << used << " ms." << endl;
#define PRINT_SORT_TEST_TICKS() \
sort(g_statistics.begin(), g_statistics.end()); \
struct StatisticPrinter { \
StatisticPrinter() : order(0) {} \
void operator() (const Statistic& stat) { \
++order; \
cout << "sort order: " << order << endl \
<< stat; \
} \
int order; \
} printer; \
cout << "---------Statistics informations(sorting ascendent)-------" << endl << endl; \
for_each(g_statistics.begin(), g_statistics.end(), printer);\
cout << "----------------------------------------------------------" << endl;
void test_stdstring_append()
{
string str;
BEGIN_TICK();
for (int i=0; i<TEST_TIMES; i++) {
str.append(APPEND_CONTENT);
}
END_AND_PRINT_TICK("std::string append");
cout << "string length: " << str.length() << endl;
}
void test_stdstring_append_operator()
{
string str;
BEGIN_TICK();
for (int i=0; i<TEST_TIMES; i++) {
str += APPEND_CONTENT;
}
END_AND_PRINT_TICK("std::string += operator");
cout << "string length: " << str.length() << endl;
}
void test_stdostringstream()
{
ostringstream oss;
BEGIN_TICK();
for (int i=0; i<TEST_TIMES; i++) {
oss << APPEND_CONTENT;
}
END_AND_PRINT_TICK("std::ostringstream <<");
cout << "string length: " << oss.str().length() << endl;
}
void test_stdostringstream_preallocate()
{
ostringstream oss;
BEGIN_TICK();
for (int i=0; i<TEST_TIMES; i++) {
oss << APPEND_CONTENT;
}
END_AND_PRINT_TICK("std::ostringstream <<");
cout << "string length: " << oss.str().length() << endl;
}
void test_stdstring_append_operator_preallocate()
{
string str;
str.reserve(PREALLOCATE_SIZE);
cout << "capacity: " << str.capacity() << endl
<< "size: " << str.size() << endl;
//assert(str.capacity() == 1024*1024*512);
BEGIN_TICK();
for (int i=0; i<TEST_TIMES; i++) {
str += APPEND_CONTENT;
}
END_AND_PRINT_TICK("hava resize(PREALLOCATE_SIZE) std::string += operator");
cout << "string length: " << str.length() << endl;
}
void test_c_strcat_append()
{
char* pstr = (char*)malloc(PREALLOCATE_SIZE);
memset(pstr, 0, sizeof(pstr));
BEGIN_TICK();
for (int i=0; i<TEST_TIMES; i++) {
strcat(pstr, APPEND_CONTENT);
}
END_AND_PRINT_TICK("c string function strcat:");
cout << "string length: " << strlen(pstr) << endl;
free(pstr);
pstr = NULL;
}
void test_c_memcpy_append()
{
//Allocate memory
char* pstr = (char*)malloc(PREALLOCATE_SIZE);
if (NULL == pstr) {
cerr << "Can't allocate memory." << endl;
return;
}
memset(pstr, 0, PREALLOCATE_SIZE);
BEGIN_TICK();
int len = 0;
for (int i=0; i<TEST_TIMES; i++) {
memcpy(pstr + len, APPEND_CONTENT, strlen(APPEND_CONTENT));
len += strlen(APPEND_CONTENT);
}
END_AND_PRINT_TICK("C language memcpy append");
cout << "string length: " << strlen(pstr) << endl;
//Cleanup
free(pstr);
pstr = NULL;
}
void test_mfc_cstring_append()
{
CString str;
BEGIN_TICK();
for (int i=0; i<TEST_TIMES; i++) {
str.Append(APPEND_CONTENT);
}
END_AND_PRINT_TICK("MFC CString append");
cout << "string length: " << str.GetLength() << endl;
}
void test_mfc_cstring_append_operator()
{
CString str;
BEGIN_TICK();
for (int i=0; i<TEST_TIMES; i++) {
str += APPEND_CONTENT;
}
END_AND_PRINT_TICK("MFC CString operator append");
cout << "string length: " << str.GetLength() << endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
#ifdef _DEBUG
cout << "DEBUG version." << endl;
#else
cout << "Release version." << endl;
#endif
cout << "TEST_TIME: " << TEST_TIMES << endl;
test_c_memcpy_append();
test_stdstring_append_operator();
test_stdstring_append();
test_stdostringstream();
test_stdstring_append_operator_preallocate();
test_mfc_cstring_append();
test_mfc_cstring_append_operator();
test_c_strcat_append();
PRINT_SORT_TEST_TICKS();
return 0;
}
请接下部。。。