簡體   English   中英

C++ unordered_map<string, ...> 查找而不構造字符串</string,>

[英]C++ unordered_map<string, ...> lookup without constructing string

我有 C++ 代碼,用於調查 BIG 字符串並匹配大量子字符串。 我盡可能避免構造 std::strings,方法是像這樣對子字符串進行編碼:

char* buffer, size_t bufferSize

然而,在某些時候,我想在其中一個中查找 substring:

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

所以,為此,我 go:

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

構造一個 std::string 的唯一目的是查找。

我覺得我可以在這里做一個優化,通過...將 unordered_map 的鍵類型更改為某種臨時字符串冒名頂替者,像這樣的 class...

class SubString
{
    char* buffer;
    size_t bufferSize;

    // ...
};

... 執行與 std::string 到 hash 相同的邏輯並進行比較,但是當它被銷毀時不會釋放它的緩沖區。

所以,我的問題是:有沒有辦法讓標准類做到這一點,還是我自己寫這個 class?

您想要做的是異構查找 從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 ,你可以避免創建這么多的字符串臨時代碼,方法是在你可以重新分配值的unordered_map旁邊存儲一個std::string成員,然后將該string傳遞給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);
        } 
    };
};

然后,您可以從std::string s構造CharPtrOrString ,以便在無序容器鍵中使用,但每次調用find時,都可以從const char*廉價構造一個。 請注意, operator== above必須解決您所做的事情(使用的約定是指針的nullptr然后使用std::string成員),因此它會比較正在使用的成員。 散列函數必須確保具有特定文本值的std::string將產生與const char*相同的散列(默認情況下它不會與GCC 7.3和/或Clang 6一起使用 - 我同時使用它們並記住一個有問題,但沒有問題)。

在 C++20 中,您現在可以這樣做:

// struct is from "https://www.cppstories.com/2021/heterogeneous-access-cpp20/"
struct string_hash {
    using is_transparent = void;
    [[nodiscard]] size_t operator()(const char *txt) const {
        return std::hash<std::string_view>{}(txt);
    }
    [[nodiscard]] size_t operator()(std::string_view txt) const {
        return std::hash<std::string_view>{}(txt);
    }
    [[nodiscard]] size_t operator()(const std::string &txt) const {
        return std::hash<std::string>{}(txt);
    }
};


// Declaration of map
std::unordered_map<std::string, Info, string_hash, std::equal_to<>> map;

std::string_view key = "foo";
if (map.find(key))
{
    // do something here
}

請注意,使用[]時您仍然需要std::string 可能有辦法解決這個問題,但我不太確定

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM