我怎么能加快比较std :: string与字符串文字?

我有一堆代码,其中std::string类型的对象与字符串文字进行比较。 像这样的东西:

//const std:string someString = //blahblahblah;
if( someString == "(" ) {
   //do something
} else if( someString == ")" ) {
   //do something else
} else if// this chain can be very long

比较时间累积到一个很大的数量(是的,我简介),所以它会很快加快。

该代码将字符串与许多短字符串进行比较,这种比较难以避免。 留下声明为std::string很可能是不可避免的 - 有那么几行代码。 留下字符串文字和与==比较也可能是不可避免的 - 重写整个代码将是一个痛苦。

问题在于Visual C ++ 11附带的STL实现使用了一些奇怪的方法。 ==映射到std::operator==(const basic_string&, const char*) ,它调用basic_string::compare( const char* ) ,后者又调用std::char_traits<char>( const char* ) ,它调用strlen()来计算字符串文字的长度。 然后比较运行两个字符串,并将两个字符串的长度传递给该比较。

编译器很难分析所有这些,并发出遍历字符串文字两次的代码。 对于短文字来说,时间不长,但每次比较都需要遍历文字两次而不是一次。 简单地调用strcmp()很可能会更快。

有什么我可以做的,比如编写一个自定义的比较器类,这有助于避免在这种情况下遍历字符串文字两次?


与Dietmar的解决方案类似,但编辑稍少:您可以包装字符串(一次)而不是每个文字

#include <string>
#include <cstring>
struct FastLiteralWrapper {
    std::string const &s;

    explicit FastLiteralWrapper(std::string const &s_) : s(s_) {}

    template <std::size_t ArrayLength>
    bool operator== (char const (&other)[ArrayLength]) {
        std::size_t const StringLength = ArrayLength - 1;
        return StringLength == s.size()
            && std::memcmp(s.data(), other, StringLength) == 0;
    }
};

你的代码变成:

const std:string someStdString = "blahblahblah";
// just for the context of the comparison:
FastLiteralWrapper someString(someStdString);
if( someString == "(" ) {
   //do something
} else if( someString == ")" ) {
   //do something else
} else if// this chain can be very long

NB。 最快的解决方案 - 以更多编辑为代价 - 可能会为枚举的常量构建一个(完美)哈希或trie映射字符串文本,然后switch查找的值。 if / else if链通常闻到不好的国际海事组织长。


那么,除了C ++ 14的string_literal ,你可以很容易地编写一个解决方案:

  • 为了与单个字符进行比较,请使用字符文字和:

    bool operator==(const std::string& s, char c)
    {
      return s.size() == 1 && s[0] == c;
    }
    
  • 为了与字符串文字进行比较,您可以使用如下所示的内容:

    template<std::size_t N>
    bool operator==(const std::string& s, char const (&literal)[N])
    {
      return s.size() == N && std::memcmp(s.data(), literal, N-1) == 0;
    }
    
  • 免责声明:

  • 第一个可能甚至是多余的,
  • 只有在你对自己所拥有的东西进行了改进之后才能做到这一点

  • 如果您需要比较长串字符串,则可能需要将前缀与组通用处理进行比较。 尤其是当比较一组已知的字符串与输入字符串的相等性时,还可以选择使用完美散列,并将这些操作的关键字由这些字符生成的整数关闭。

    由于完美散列的使用可能具有最佳性能,但也需要对代码布局进行重大更改,因此可以在编译时确定字符串文字的大小,并在比较时使用此大小。 例如:

    class Literal {
        char const* d_base;
        std::size_t d_length;
    public:
        template <std::size_t Length>
        Literal(char const (&base)[Length]): d_base(base), d_length(Length - 1) {}
        bool operator== (std::string const& other) const {
            return other.size() == this->d_length
                && !other.memcmp(this->d_base, other.c_str(), this->d_length);
        }
        bool operator!=(std::string const& other) const { return !(*this == other); }
    };
    bool operator== (std::string const& str, Literal const& literal) {
        return literal == str;
    }
    bool operator!= (std::string const& str, Literal const& literal) {
        return !(str == literal);
    }
    

    显然,这假定您的文字不会嵌入除隐式添加的终止空字符以外的空字符(' 0'),否则静态长度会被扭曲。 使用C ++ 11 constexpr将有可能防范这种可能性,但代码在没有任何理由的情况下会变得更加复杂。 然后你会使用类似的东西比较你的字符串

    if (someString == Literal("(")) {
        ...
    }
    else if (someString == Literal(")")) {
        ...
    }
    
    链接地址: http://www.djcxy.com/p/72127.html

    上一篇: How could I speed up comparison of std::string against string literals?

    下一篇: Difference between string object and string literal