std::处理短字符串的字符串性能 Bjarne Stroustrup和其他专家表示C++在处理短字符串和时比C快。
但是在我的测试中,std::处理短字符串的字符串性能 Bjarne Stroustrup和其他专家表示C++在处理短字符串和时比C快。,c++,C++,但是在我的测试中,C++比C慢了大约110% g++版本为4.4.6(在CentOS 6.3上运行)。这是因为g++4.4.6的c++11特性较少,例如右值引用(移动语义) 测试结果 $time a.out input_文件的输出减去不调用compose_X()函数的执行时间 cpp版本:0.192秒 C版本:0.091秒 源代码 使用-O2 编辑 compose\u cpp()和compose\u p()来自比亚恩的文章。他说compose\u-cpp()比compose\u-p()更复杂
C++
比C
慢了大约110%
g++版本为4.4.6(在CentOS 6.3上运行)。这是因为g++4.4.6的c++11特性较少,例如右值引用(移动语义)
测试结果
$time a.out input_文件的输出
减去不调用compose_X()
函数的执行时间
- cpp版本:0.192秒
- C版本:0.091秒
-O2
编辑
compose\u cpp()
和compose\u p()
来自比亚恩的文章。他说compose\u-cpp()
比compose\u-p()
更复杂。我想用真实的测试来检验这个事实
如果我的测试方法错误,如何改进测试
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
std::string compose_cpp(const std::string& name, const std::string& domain)
{
return name + '@' + domain;
}
char* compose_c(const char* name, const char* domain)
{
char* res = (char*) malloc(strlen(name)+strlen(domain)+2);
char* p = strcpy(res,name);
p += strlen(name);
*p = '@';
strcpy(p+1,domain);
return res;
}
int main(int argc, char* argv[])
{
std::ifstream ifs;
ifs.open(argv[1]);
std::string email, domain;
while (ifs.good())
{
ifs >> email;
ifs >> domain;
// std::string composed = compose_cpp(email, domain);
char* composed = compose_c(email.c_str(), domain.c_str());
free(composed);
}
ifs.close();
}
我只是想在这里做一个猜测,因为我没有要测试的数据文件。我认为你的结果可能不符合Stroustrup的预期,因为他在这里说:
是的,C++版本,因为它不必对参数字符进行计数,也不使用空闲存储(动态内存)来实现短参数字符串。 然而,我的理解是,
libstdc++
对所有字符串使用动态内存(零长度字符串除外)。请参阅这篇最近的SO,它回答了一个关于libstdc++
中std::string
对象的小尺寸的问题:
使用短字符串优化的实现(比如MSVC,我不确定clang的libc++是否使用它)可能会获得更好的结果。我只是在这里猜测一下,因为我没有数据文件来测试。我认为你的结果可能不符合Stroustrup的预期,因为他在这里说:
是的,C++版本,因为它不必对参数字符进行计数,也不使用空闲存储(动态内存)来实现短参数字符串。 然而,我的理解是,
libstdc++
对所有字符串使用动态内存(零长度字符串除外)。请参阅这篇最近的SO,它回答了一个关于libstdc++
中std::string
对象的小尺寸的问题:
使用短字符串优化的实现(比如MSVC——我不确定clang的libc++是否使用它)可能会获得更好的结果。我冒昧地扩展了一点测试程序。特别是,我添加了代码,使它在内部生成数据,而不是依赖外部文件,添加了用于隔离字符串处理的定时代码,并且在相同的运行中,它同时完成了字符串操作的C++和C版本,因此它立即产生了我可以比较的结果。这给了我以下代码:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <ctime>
char* compose_c(const char* name, const char* domain)
{
char* res = (char*) malloc(strlen(name)+strlen(domain)+2);
char* p = strcpy(res,name);
p += strlen(name);
*p = '@';
strcpy(p+1,domain);
return res;
}
std::string rand_string(int size){
std::string ret;
for (int i = 0; i < size; i++)
ret.push_back(rand() % 10 + '0');
return ret;
}
struct address {
std::string email, domain;
address() : email(rand_string(5)), domain(rand_string(4) + ".com") { }
};
struct composed {
std::string addr;
composed(address const &a) : addr(a.email + "@" + a.domain) {}
};
void report(clock_t d, std::string const &label){
std::cout << double(d) / CLOCKS_PER_SEC << " seconds for " << label << "\n";
}
int main(int argc, char **argv) {
static const int NUM = 1024 * 1024;
std::vector<address> addresses(NUM);
clock_t start = clock();
{
std::vector<composed> c{ addresses.begin(), addresses.end() };
}
report(clock() - start, "C++");
std::vector<char *> c_results(addresses.size());
clock_t start_c = clock();
for (int i = 0; i < addresses.size(); i++)
c_results[i] = compose_c(addresses[i].email.c_str(), addresses[i].domain.c_str());
for (char *c : c_results)
free(c);
report(clock() - start_c, "C");
}
<> P>虽然从运行到运行有一些变化,但这些代码是相当有代表性的结果——C代码几乎(但不完全)两倍于C++代码。
请注意,尽管我实际上给了C版本一点不公平的优势,但这是事实。C++代码的时间不仅包括做字符串操作的时间,还包括创建和销毁向量以保存结果的时间。对于C代码,我提前准备了向量,然后只花时间让代码自己创建和销毁字符串
为了确保这个结果不是偶然的,我还尝试改变了一些自变量。例如,将我们编写的地址字符串的数量增加10倍会增加总时间,但对比率几乎没有影响:
0.714 seconds for C++
1.206 seconds for C
同样,改变顺序,使C代码先运行,C++代码第二次运行,没有明显的效果。 我想我应该补充一点:诚然,目前为止,这段代码并没有像最初那样使用
compose\u cpp
函数,而是选择将功能合并到composed
的构造函数中。为了完整起见,我确实编写了一个使用compose\u cpp
的版本,如下所示:
std::vector<std::string> composed;
composed.reserve(NUM);
clock_t start = clock();
for (auto const &a : addresses)
composed.push_back(compose_cpp(a.email, a.domain));
但是,这些结果在很大程度上取决于标准库的实现,特别是std::string
实现了短字符串优化。在相同的硬件上运行相同的代码,但使用缺乏这种优化的实现(在我的例子中,是gcc 4.9.1的nuwen MinGW发行版)会产生完全不同的结果:
2.689 seconds for C++
1.131 seconds for C
在这种情况下,C代码比VC++中的代码快一点,但是C++代码的速度减慢了大约4。我尝试了一些不同的编译器标志(-O2 vs.-O3,等等),但它们的效果很小——在这个测试中,缺少短字符串优化显然是其他因素的主要原因
底线:我认为这证实了C++代码可以比C代码快得多,但是实现这个速度更多的取决于实现的质量。如果实现无法提供短字符串优化,C++代码可以比C版本更快2X慢,而不是2X。
< P>我有一点自由地扩展了您的测试程序。特别是,我添加了代码,使它在内部生成数据,而不是依赖外部文件,添加了用于隔离字符串处理的定时代码,并且在相同的运行中,它同时完成了字符串操作的C++和C版本,因此它立即产生了我可以比较的结果。这给了我以下代码:#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <ctime>
char* compose_c(const char* name, const char* domain)
{
char* res = (char*) malloc(strlen(name)+strlen(domain)+2);
char* p = strcpy(res,name);
p += strlen(name);
*p = '@';
strcpy(p+1,domain);
return res;
}
std::string rand_string(int size){
std::string ret;
for (int i = 0; i < size; i++)
ret.push_back(rand() % 10 + '0');
return ret;
}
struct address {
std::string email, domain;
address() : email(rand_string(5)), domain(rand_string(4) + ".com") { }
};
struct composed {
std::string addr;
composed(address const &a) : addr(a.email + "@" + a.domain) {}
};
void report(clock_t d, std::string const &label){
std::cout << double(d) / CLOCKS_PER_SEC << " seconds for " << label << "\n";
}
int main(int argc, char **argv) {
static const int NUM = 1024 * 1024;
std::vector<address> addresses(NUM);
clock_t start = clock();
{
std::vector<composed> c{ addresses.begin(), addresses.end() };
}
report(clock() - start, "C++");
std::vector<char *> c_results(addresses.size());
clock_t start_c = clock();
for (int i = 0; i < addresses.size(); i++)
c_results[i] = compose_c(addresses[i].email.c_str(), addresses[i].domain.c_str());
for (char *c : c_results)
free(c);
report(clock() - start_c, "C");
}
<> P>虽然从运行到运行有一些变化,但这些代码是相当有代表性的结果——C代码几乎(但不完全)两倍于C++代码。
请注意,尽管我实际上给了C版本一点不公平的优势,但这是事实。C++代码的定时
0.631 seconds for C++
1.21 seconds for C
2.689 seconds for C++
1.131 seconds for C