C ++ unordered_map <string,... =“”>查找而不构造字符串

时间:2018-04-07 16:32:48

标签: c++ string c++11 unordered-map

我有C ++代码,用于调查BIG字符串并匹配大量子字符串。尽可能地,我通过编码这样的子串来避免构造std :: strings:

char* buffer, size_t bufferSize

然而,在某些时候,我想在其中一个中查找子字符串:

std::unordered_map<std::string, Info> stringToInfo = {...

所以,为此,我去了:

stringToInfo.find(std::string(buffer, bufferSize))

为了查找的目的,构造一个std :: string。

我觉得我可以在这里进行优化,通过...将unordered_map的键类型更改为某种临时字符串冒名者,这样的类......

class SubString
{
    char* buffer;
    size_t bufferSize;

    // ...
};

...它使用与std :: string相同的逻辑来进行哈希和比较,但是当它被破坏时不会释放它的缓冲区。

所以,我的问题是:有没有办法让标准类来做这个,或者我自己写这个类?

1 个答案:

答案 0 :(得分:4)

您想要做的是异构查找。从C ++ 14开始,std::map::findstd::set::find支持它(注意函数的版本(3)和(4),这些函数是在查找值类型上模板化的)。对于无序容器,它更复杂,因为需要告知或查找将为同一文本生成相同哈希值的所有键类型的哈希函数。正在考虑未来标准的提案:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0919r0.html

同时,您可以使用另一个已支持异构查找的库,例如boost::unordered_map::find

如果你想坚持std::unordered_map,你可以避免创建这么多字符串临时代码,方法是在std::string旁边存储unordered_map成员,你可以重新分配值,然后传递string {1}}到find。您可以将其封装在自定义容器类中。

另一种方法是编写一个自定义类作为无序容器密钥:

struct CharPtrOrString
{
    const char* p_;
    std::string s_;

    explicit CharPtrOrString(const char* p) : p_{p} { }
    CharPtrOrString(std::string s) : p_{nullptr}, s_{std::move(s)} { }

    bool operator==(const CharPtrOrString& x) const
    {
        return p_ ? x.p_ ? std::strcmp(p_, x.p_) == 0
                         : p_ == x.s_
                  : x.p_ ? s_ == x.p_
                         : s_ == x.s_;
    }

    struct Hash
    {
        size_t operator()(const CharPtrOrString& x) const
        {
            std::string_view sv{x.p_ ? x.p_ : x.s_.c_str()};
            return std::hash<std::string_view>()(sv);
        } 
    };
};

然后,您可以从CharPtrOrString构建std::string以用于无序容器键,但每次调用const char*时,只需从find便宜地构建一个。{1}}。请注意,上面的operator==必须解决您所做的事情(使用的约定是指针的nullptr然后使用std::string成员),因此它会比较正在使用的成员。哈希函数必须确保具有特定文本值的std::string将产生与const char*相同的哈希值(默认情况下,它,使用GCC 7.3和/或者Clang 6 - 我和两个人一起工作,记住一个有问题,但没有问题。