我怎么能加快比较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?