George Robinson
George Robinson

Reputation: 2125

Hash & EqualTo functions for unordered_set<BSTR>

In a code, that inserts the Windows style OLE strings (BSTR's) into the good ol' STL container - the unordered_map<BSTR>, I declared the unordered_set, like this:

unordered_set<BSTR, std::hash<std::wstring>, std::equal_to<std::wstring>> usetBstr;

expecting BSTR strings to act like wstrings.

Everything seemed to work fine, until one day a BSTR with a zero wchar in the middle of the string was emplaced into the unordered_set.

Of course!, when the compiler converts the BSTR to a std::wstring, it stops at the first null terminator it finds in the string, because wstrings are not really BSTR strings (which keep their length in memory word immediately preceding the BSTR data and wstrings keep their length somewhere else).

Question: What Hash and EqualTo functions from the STL library would be appropriate for the unordered_map<BSTR> in this case?

P.S. Of course I could roll out my own functions, but I prefer to wrap something already in the standard.

Upvotes: 0

Views: 212

Answers (1)

NathanOliver
NathanOliver

Reputation: 180585

The problem with using std::hash<std::wstring> and std::equal_to<std::wstring> is that when the compiler converts the BSTR to a std::wstring, it stops at the first null terminator it finds in the string. This means "this\0\0" and "this\0" become the same string when it hashes and checks for equality.

What you need to provide an adapter that that passes a properly construct std::wstring/std::wstring_view to the hash and equality functions. You can do that by creating your own functors like

struct BSTR_hash
{
    std::size_t operator()(BSTR const& s) const noexcept
    {
        return std::hash<std::wstring_view>{}({s, SysStringLen(s)});
    }
};
struct BSTR_equal_to
{
    bool operator()(BSTR const& lhs, BSTR const& rhs) const noexcept
    {
        return std::wstring_view(lhs, SysStringLen(lhs)) == std::wstring_view(rhs, SysStringLen(rhs));
    }
};

unordered_set<BSTR, BSTR_hash, BSTR_equal_to> usetBstr;

Upvotes: 2

Related Questions