与C字符串(`malloc` +`memcpy`)相比,`std :: string`的性能真的很糟糕

Alb*_*ert 1 c++ string stl visual-studio-2012

我只是偶然发现了非常糟糕的表现std::string.我预计std::string来自某些外部数据(例如std::string(X.c_str()))的新创建将大致等同于data = malloc(X.size())+ strcpy(data, X.c_str()),具有一些微小的恒定开销.

一些示例性能代码:

#include <string>
#include <string.h>
#include <assert.h>

static const char SampleString[] =
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
    "Hello world. Hello world. Hello world. Hello world. Hello world. "
;

static size_t N = 1000000;

// mostly for avoiding compiler optimization
void readStr(const char* _s) {
    volatile const char* s = _s;
    while(*s) ++s;
}

void cppStringLoop1() {
    for(size_t i = 0; i < N; ++i) {
        std::string tmp(SampleString);
        readStr(&tmp[0]);
    }
}

void cppStringLoop2() {
    for(size_t i = 0; i < N; ++i) {
        std::string tmp(SampleString, SampleString + sizeof(SampleString));
        readStr(&tmp[0]);
    }
}

void cStringLoop() {
    for(size_t i = 0; i < N; ++i) {
        char* tmp = (char*) malloc(sizeof(SampleString));
        memcpy(tmp, SampleString, sizeof(SampleString));
        readStr(tmp);
        free(tmp);
    }
}

int main(int argc, char** argv) {
    assert(argc >= 2);
    if(strcmp(argv[1], "-c") == 0) cStringLoop();
    else if(strcmp(argv[1], "-c++1") == 0) cppStringLoop1();
    else if(strcmp(argv[1], "-c++2") == 0) cppStringLoop2();
    else assert(false);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

似乎MSVC处于发布模式,我的初步假设是正确的.(发布模式= MSVC发布运行时lib +优化.)

但是,在调试模式(MSVC Debug Runtime lib + no optimizations)中,看起来这个假设是错误的.开销不是很小(约175%).

也许这也是MSVC 2012的std::string实施.这里有一些数字:

$ time ./TestStringPerf.exe -c

real    0m6.879s
user    0m0.015s
sys     0m0.015s

$ time ./TestStringPerf.exe -c++1

real    0m10.524s
user    0m0.000s
sys     0m0.000s

$ time ./TestStringPerf.exe -c++2

real    0m10.106s
user    0m0.000s
sys     0m0.015s
Run Code Online (Sandbox Code Playgroud)

或许这只是期望的开销.

Sim*_*ple 8

你继续使用sizeof(SampleString).SampleString是一个指针.因此,您的C代码和cppStringLoop2功能仅复制大约4-8个字符.

你需要:

  • 改变你的用途sizeof(SampleString)std::strlen(SampleString);
  • 或更改static const char* SampleStringstatic const char SampleString[]并使用sizeof(SampleString)在一些地方和sizeof(SampleString) - 1其他一些国家(即cppStringLoop2功能).