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

前端 未结 14 2094
心在旅途
心在旅途 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:12

    Well there are definitely known problems regarding the performance of strings and other containers. Most of them have to do with temporaries and unnecessary copies.

    It's not too hard to use it right, but it's also quite easy to Do It Wrong. For example, if you see your code accepting strings by value where you don't need a modifiable parameter, you Do It Wrong:

    // you do it wrong
    void setMember(string a) {
        this->a = a; // better: swap(this->a, a);
    }
    

    You better had taken that by const reference or done a swap operation inside, instead of yet another copy. Performance penalty increases for a vector or list in that case. However, you are right definitely that there are known problems. For example in this:

    // let's add a Foo into the vector
    v.push_back(Foo(a, b));
    

    We are creating one temporary Foo just to add a new Foo into our vector. In a manual solution, that might create the Foo directly into the vector. And if the vector reaches its capacity limit, it has to reallocate a larger memory buffer for its elements. What does it do? It copies each element separately to their new place using their copy constructor. A manual solution might behave more intelligent if it knows the type of the elements before-hand.

    Another common problem is introduced temporaries. Have a look at this

    string a = b + c + e;
    

    There are loads of temporaries created, which you might avoid in a custom solution that you actually optimize onto performance. Back then, the interface of std::string was designed to be copy-on-write friendly. However, with threads becoming more popular, transparent copy on write strings have problems keeping their state consistent. Recent implementations tend to avoid copy on write strings and instead apply other tricks where appropriate.

    Most of those problems are solved however for the next version of the Standard. For example instead of push_back, you can use emplace_back to directly create a Foo into your vector

    v.emplace_back(a, b);
    

    And instead of creating copies in a concatenation above, std::string will recognize when it concatenates temporaries and optimize for those cases. Reallocation will also avoid making copies, but will move elements where appropriate to their new places.

    For an excellent read, consider Move Constructors by Andrei Alexandrescu.

    Sometimes, however, comparisons also tend to be unfair. Standard containers have to support the features they have to support. For example if your container does not keep map element references valid while adding/removing elements from your map, then comparing your "faster" map to the standard map can become unfair, because the standard map has to ensure that elements keep being valid. That was just an example, of course, and there are many such cases that you have to keep in mind when stating "my container is faster than standard ones!!!".

提交回复
热议问题