std::hash
來自 cppreference.com
定義於標頭檔案 <bitset> |
||
定義於標頭檔案 <coroutine> |
||
定義於標頭檔案 <chrono> |
(C++26 起) |
|
定義於標頭檔案 <filesystem> |
||
定義於標頭檔案 <functional> |
||
定義於標頭檔案 <memory> |
||
定義於標頭檔案 <optional> |
||
定義於標頭檔案 <stacktrace> |
||
定義於標頭檔案 <string> |
||
定義於標頭檔案 <string_view> |
||
定義於標頭檔案 <system_error> |
||
定義於標頭檔案 <text_encoding> |
||
定義於標頭檔案 <thread> |
||
定義於標頭檔案 <typeindex> |
||
定義於標頭檔案 <variant> |
||
在標頭檔案 <vector> 中定義 |
||
template< class Key > struct hash; |
(C++11 起) | |
無序關聯容器 std::unordered_set、std::unordered_multiset、std::unordered_map、std::unordered_multimap 使用模板 std::hash
的特化作為預設雜湊函式。
給定型別 Key
,std::hash<Key>
的每個特化要麼是啟用的,要麼是停用的。
- 如果程式或使用者未提供
std::hash<Key>
,則它被停用。 - 否則,如果滿足以下所有條件,則
std::hash<Key>
被啟用:
- 滿足以下所有要求:
- Hash(其中
Key
作為函式呼叫引數型別) - DefaultConstructible(可預設構造)
- CopyAssignable(可複製賦值)
- Swappable(可交換)
- Hash(其中
- 給定以下值:
- h,型別為
std::hash<Key>
的物件。 - k1 和 k2,型別為
Key
的物件。
- h,型別為
- 滿足以下所有要求:
- 如果 k1 == k2 為 true,則 h(k1) == h(k2) 也為 true。
- 除非
std::hash<Key>
是程式定義的特化,否則 h(k1) 永遠不會丟擲異常。
- 否則,
std::hash<Key>
被停用。
停用的特化不滿足 Hash,不滿足 FunctionObject,並且以下所有值為 false:
- std::is_default_constructible<std::hash<Key>>::value
- std::is_copy_constructible<std::hash<Key>>::value
- std::is_move_constructible<std::hash<Key>>::value
- std::is_copy_assignable<std::hash<Key>>::value
- std::is_move_assignable<std::hash<Key>>::value
換句話說,它們存在,但無法使用。
巢狀型別
|
(C++20 前) |
[編輯] 成員函式
構造雜湊函式物件 (公開成員函式) | |
計算引數的雜湊值 (公開成員函式) |
[編輯] 標準庫特化
每個宣告模板 std::hash
的標頭檔案也為以下型別提供 std::hash
的啟用特化:
- 所有 cv 非限定算術型別
- 所有 cv 非限定列舉型別
- 所有 cv 非限定指標型別
- std::nullptr_t
此外,一些標頭檔案還為庫型別提供其他啟用的 std::hash
特化(參見下方)。
對於標準庫提供的所有
|
(C++17 起) |
[編輯] 庫型別的特化
[編輯] 注意
實際的雜湊函式是依賴於實現的,並且除了上面指定的之外,不要求滿足任何其他質量標準。值得注意的是,一些實現使用平凡的(同一性)雜湊函式,將整數對映到自身。換句話說,這些雜湊函式旨在與無序關聯容器一起使用,但不適用於加密雜湊等用途。
雜湊函式僅要求在程式的單次執行中對相同輸入產生相同的結果;這允許使用加鹽雜湊來防止碰撞拒絕服務攻擊。
沒有為 C 字串提供特化。 std::hash<const char*> 產生指標值(記憶體地址)的雜湊,它不檢查任何字元陣列的內容。
對於 std::pair 和標準容器型別的附加特化,以及用於組合雜湊的實用函式,可在 boost::hash
中找到。
[編輯] 示例
執行此程式碼
#include <cstddef> #include <functional> #include <iomanip> #include <iostream> #include <string> #include <unordered_set> struct S { std::string first_name; std::string last_name; bool operator==(const S&) const = default; // since C++20 }; // Before C++20. // bool operator==(const S& lhs, const S& rhs) // { // return lhs.first_name == rhs.first_name && lhs.last_name == rhs.last_name; // } // Custom hash can be a standalone function object. struct MyHash { std::size_t operator()(const S& s) const noexcept { std::size_t h1 = std::hash<std::string>{}(s.first_name); std::size_t h2 = std::hash<std::string>{}(s.last_name); return h1 ^ (h2 << 1); // or use boost::hash_combine } }; // Custom specialization of std::hash can be injected in namespace std. template<> struct std::hash<S> { std::size_t operator()(const S& s) const noexcept { std::size_t h1 = std::hash<std::string>{}(s.first_name); std::size_t h2 = std::hash<std::string>{}(s.last_name); return h1 ^ (h2 << 1); // or use boost::hash_combine } }; int main() { std::string str = "Meet the new boss..."; std::size_t str_hash = std::hash<std::string>{}(str); std::cout << "hash(" << std::quoted(str) << ") =\t" << str_hash << '\n'; S obj = {"Hubert", "Farnsworth"}; // Using the standalone function object. std::cout << "hash(" << std::quoted(obj.first_name) << ", " << std::quoted(obj.last_name) << ") =\t" << MyHash{}(obj) << " (using MyHash) or\n\t\t\t\t" << std::hash<S>{}(obj) << " (using injected specialization)\n"; // Custom hash makes it possible to use custom types in unordered containers. // The example will use the injected std::hash<S> specialization above, // to use MyHash instead, pass it as a second template argument. std::unordered_set<S> names = {obj, {"Bender", "Rodriguez"}, {"Turanga", "Leela"}}; for (auto const& s: names) std::cout << std::quoted(s.first_name) << ' ' << std::quoted(s.last_name) << '\n'; }
可能的輸出
hash("Meet the new boss...") = 10656026664466977650 hash("Hubert", "Farnsworth") = 12922914235676820612 (using MyHash) or 12922914235676820612 (using injected specialization) "Bender" "Rodriguez" "Turanga" "Leela" "Hubert" "Farnsworth"
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
LWG 2119 | C++11 | 缺少對擴充套件整數型別的特化 | 已提供 |
LWG 2148 | C++11 | 缺少對列舉的特化 | 已提供 |
LWG 2543 | C++11 | std::hash 可能不是 SFINAE 友好的 |
變為 SFINAE 友好 |
LWG 2817 | C++11 | 缺少對 std::nullptr_t 的特化 | 已提供 |