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