How efficient is std::string compared to null-terminated strings?

前端 未结 14 2088
心在旅途
心在旅途 2020-12-28 19:23

I\'ve discovered that std::strings are very slow compared to old-fashioned null-terminated strings, so much slow that they significantly slow down my overall pr

14条回答
  •  情话喂你
    2020-12-28 20:07

    A large part of the reason might be the fact that reference-counting is no longer used in modern implementations of STL.

    Here's the story (someone correct me if I'm wrong): in the beginning, STL implementations used reference counting, and were fast but not thread-safe - the implementors expected application programmers to insert their own locking mechanisms at higher levels, to make them thread-safe, because if locking was done at 2 levels then this would slow things down twice as much.

    However, the programmers of the world were too ignorant or lazy to insert locks everywhere. For example, if a worker thread in a multi-threaded program needed to read a std::string commandline parameter, then a lock would be needed even just to read the string, otherwise crashes could ensue. (2 threads increment the reference count simultaneously on different CPU's (+1), but decrement it separately (-2), so the reference count goes down to zero, and the memory is freed.)

    So implementors ditched reference counting and instead had each std::string always own its own copy of the string. More programs worked, but they were all slower.

    So now, even a humble assignment of one std::string to another, (or equivalently, passing a std::string as a parameter to a function), takes about 400 machine code instructions instead of the 2 it takes to assign a char*, a slowdown of 200 times.

    I tested the magnitude of the inefficiency of std::string on one major program, which had an overall slowdown of about 100% compared with null-terminated strings. I also tested raw std::string assignment using the following code, which said that std::string assignment was 100-900 times slower. (I had trouble measuring the speed of char* assignment). I also debugged into the std::string operator=() function - I ended up knee deep in the stack, about 7 layers deep, before hitting the 'memcpy()'.

    I'm not sure there's any solution. Perhaps if you need your program to be fast, use plain old C++, and if you're more concerned about your own productivity, you should use Java.

    #define LIMIT 800000000
    clock_t start;
    std::string foo1 = "Hello there buddy";
    std::string foo2 = "Hello there buddy, yeah you too";
    std::string f;
    
    start = clock();
    for (int i=0; i < LIMIT; i++) {
        stop();
        f    = foo1;
        foo1 = foo2;
        foo2 = f;
    }
    double stl = double(clock() - start) / CLOCKS_PER_SEC;
    
    start = clock();
    for (int i=0; i < LIMIT; i++) {
        stop();
    }
    double emptyLoop = double(clock() - start) / CLOCKS_PER_SEC;
    
    char* goo1 = "Hello there buddy";
    char* goo2 = "Hello there buddy, yeah you too";
    char *g;
    
    start = clock();
    for (int i=0; i < LIMIT; i++) {
        stop();
        g = goo1;
        goo1 = goo2;
        goo2 = g;
    }
    double charLoop = double(clock() - start) / CLOCKS_PER_SEC;
    
    TfcMessage("done", 'i', "Empty loop = %1.3f s\n"
                            "char* loop = %1.3f s\n"
                            "std::string loop = %1.3f s\n\n"
                            "slowdown = %f", 
                            emptyLoop, charLoop, stl, 
                            (stl - emptyLoop) / (charLoop - emptyLoop));
    

提交回复
热议问题